確かにそのようなことはできますが、ソース コードの直感性が損なわれることは明らかです。これを想像してください:
if if == 1
実際に実装する限り、レクサーを変更する必要はまったくありません。レクサーがソースの「if」に一致する場合、IF
タイプを持つトークンを返します。次の割り当てステートメントがあるとします。ここif
で、 は変数名で、値 1 が割り当てられています。
if <- 1;
パーサーに供給されるレクサーのトークン ストリームは次のとおりです。
IF, LARROW, INTLITERAL, SEMICOLON
割り当てステートメント (\w integer 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
現在のトークンに一致する非終端記号の2 番目の生成があり、最終的に割り当てステートメントに一致します。
AssignmentStatement
は、次のように定義された AST ノードです。
class AssignmentStatement {
String varName;
int intVal;
AssignmentStatement(String s, int i){varName = s; intVal = i; }
}
ソースが構文的に正しいとパーサーが判断すると、他に影響はありません。変数の名前は、コンパイルの後半の段階に影響を与えるべきではありません。つまり、それを可能にする条件を作成しない場合です。