你绝对可以做这样的事情,但显然它会破坏源代码的直观性。想象一下:
if if == 1
就实际实现而言,词法分析器根本不需要更改。如果词法分析器匹配源中的“if”,它会返回一个带有IF
类型的标记。假设我们有下面的赋值语句,其中if
是一个变量名,它被赋值为 1。
if <- 1;
要馈送到解析器的词法分析器的令牌流是:
IF, LARROW, INTLITERAL, SEMICOLON
我可能有以下产品来描述赋值语句(\w 整数 rvals):
assignStmt::= id:i LARROW intExpr:e SEMICOLON {: RESULT = new AssignmentStatement(i, e) :}
intExpr::= INTLITERAL:i {: RESULT = i.intVal; :}
id::= ID:i {: RESULT = i.strVal; :}
LARROW
, ID
, IF
, INTLITERAL
, 和SEMICOLON
是终结符,它们是词法分析器返回的标记,并且assignStmt
, id
, 和intExpr
是非终结符。ID
表示一个标识符(例如类/变量/方法名)。
在 if 语句的产生式失败后,我们最终将输入赋值语句的第一个产生式。我们扩展id
非终端,其唯一的生产是ID
,但我要匹配的令牌是IF
,所以assignStmt
生产完全失败。
为了让我的语言允许将变量命名为“if”,我所要做的就是:
assignStmt::= id:i LARROW intExpr:e SEMICOLON {: RESULT = new AssignmentStatement(i, e) :}
intExpr::= INTLITERAL:i {: RESULT = i.intVal; :}
id::= ID:i {: RESULT = i.strVal; :}
|IF {: RESULT = "if"; :}
请注意,它|
定义了非终端的替代生产。现在我们有了id
非终结符的第二个产生式,它匹配当前标记,并最终匹配一个赋值语句。
AssignmentStatement
是一个 AST 节点,定义如下:
class AssignmentStatement {
String varName;
int intVal;
AssignmentStatement(String s, int i){varName = s; intVal = i; }
}
一旦解析器确定源在语法上是正确的,其他任何东西都不会受到影响。变量的名称不应影响编译的后期阶段,也就是说,如果您不创建允许这种情况发生的条件。