Вы определенно могли бы сделать такую вещь, но, очевидно, это разрушило бы интуитивность исходного кода. Представьте себе следующее:
if if == 1
Что касается фактического его осуществления, лексера не нужно было менять вообще. Если лексер соответствует «if» в источнике, он возвращает токен с типом IF
. Предположим, мы имеем следующее оператор присваивания, где if
является имя переменной, и это получение присваивается значение 1.
if <- 1;
маркер потока лексером к подаваться в парсера:
IF, LARROW, INTLITERAL, SEMICOLON
Я мог бы имеют следующие постановки, чтобы описать оператор присваивания (\ ш целочисленных 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
полностью не удается.
Для моего языка, чтобы переменный будет называться «если» все, что нужно сделать, это:
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"; :}
Обратите внимание, что |
определяет альтернативное производство для нетерминала. Теперь у нас есть второе производство для non-terminal id
, которое соответствует текущему токену и в конечном итоге приводит к сопоставлению оператора присваивания.
AssignmentStatement
является узел AST определяется следующим образом:
class AssignmentStatement {
String varName;
int intVal;
AssignmentStatement(String s, int i){varName = s; intVal = i; }
}
После того, как анализатор решает источник синтаксический правильно, ничего не должно быть затронуто. Имена ваших переменных не должны влиять на последние этапы компиляции, то есть, если вы не создаете условий, которые позволили бы это произойти.
Такие, erm, способности, будут не только «путать», но и люди, которые будут читать код на этом языке. Тогда зачем это разрешать? – kirilloid