第一部分

设计笔记

在提取token和解析结构之间有一种对称美。扫描器用token的第一个字符来判断接下来用何种类型去提取token。在token被提取后,当前字符是token的尾字符后的第一个字符(比如xy = bc,在提取到特殊符号token  "="之后,当前字符指向'b')。同样,解析器用Pascal结构的第一个token(比如复合语句的BEGIN)来判断解析何种结构类型(复合语句还是复制语句?,还是其它类型?)。在这个结构被解析后,当前的Token是结构最后一个token的下一个token。(这种对称性解释了为什么Antlr对Lexer和Parser采用一样的LL(*)解析方式)

解析语句

清单5-14 展示了frontend.pascal.parsers包中Pascal解析器子类StatementParser中的parse()和setLineNumber()方法。其中构造器如上所述获取解析上下文(获得父解析器的scanner,也就是解析的上下文)。

/**
 * 解析一个语句,以传入的token判断该进行何种解析,子类会覆盖此方法
 * @param token 语句的第一个token
 * @return 分析子树的根节点
 * @throws Exception 
 */
public ICodeNode parse(Token token)
throws Exception
   9: {
  10:     ICodeNode statementNode = null;
  11:  
switch ((PascalTokenType) token.getType()) {
  13:  
case BEGIN: {
  16:             CompoundStatementParser compoundParser =
this);
  18:             statementNode = compoundParser.parse(token);
break;
  20:         }
  21:  
//类似于 a = b 之类的赋值语句,这里a就是标识符identifier
case IDENTIFIER: {
  24:             AssignmentStatementParser assignmentParser =
this);
  26:             statementNode = assignmentParser.parse(token);
break;
  28:         }
default: {
  30:             statementNode = ICodeFactory.createICodeNode(NO_OP);
break;
  32:         }
  33:     }
  34:  
// 设置根节点“行位置”属性,即第一个token的行位置
  36:     setLineNumber(statementNode, token);
return statementNode;
  38: }
  39:  
/**
 * 设置节点的行属性。PS: 我认为这种写法很怪,为何不setLineNumber(ICodeNode, int)?
 * @param node 分析树节点
 * @param token token
 */
void setLineNumber(ICodeNode node, Token token)
  46: {
if (node != null) {
  48:         node.setAttribute(LINE, token.getLineNumber());
  49:     }
  50: }

相关文章:

  • 2021-11-20
  • 2021-12-10
  • 2022-01-14
  • 2021-08-13
  • 2021-07-25
  • 2021-08-05
  • 2021-12-31
  • 2021-07-28
猜你喜欢
  • 2021-10-16
  • 2021-09-02
  • 2021-10-20
  • 2021-07-05
  • 2021-11-27
  • 2022-01-30
  • 2022-02-21
相关资源
相似解决方案