antlr语法定义
antlr grammar definition
我对编译器理论比较陌生,我只是想创建一个语法来解析一些比较,以便稍后对其进行评估。我发现 antlr 是指定语法的强大工具。根据我在理论中学到的知识,我知道优先级较高的运算符必须比优先级较低的运算符在更深的层次上声明。此外,如果我希望某些规则保持关联,我知道我必须将递归性设置为规则的左侧。知道我已经创建了一个基本语法来使用 &&、||、!=、==、<、>、<=、>=、(,) 和 !
start
: orExpr
;
orExpr
: orExpr OR andExpr
| andExpr
;
andExpr
: andExpr AND eqNotEqExpr
| eqNotEqExpr
;
eqNotEqExpr
: eqNotEqExpr NEQ compExpr
| eqNotEqExpr EQ compExpr
| compExpr
;
compExpr
: compExpr LT compExpr
| compExpr GT compExpr
| compExpr LTEQ compExpr
| compExpr GTEQ compExpr
| notExpr
;
notExpr
: NOT notExpr
| parExpr
;
parExpr
: OPAR orExpr CPAR
| id
;
id
: INT
| FLOAT
| TRUE
| FALSE
| ID
| STRING
| NULL
;
但是在互联网上搜索我发现了一种不同的方式来指定上述语法,它不遵循我提到的关于运算符优先级和左结合性的上述规则:
start
: expr
;
expr
: NOT expr //notExpr
| expr op=(LTEQ | GTEQ | LT | GT) expr //relationalExpr
| expr op=(EQ | NEQ) expr //equalityExpr
| expr AND expr //andExpr
| expr OR expr //orExpr
| atom //atomExpr
;
atom
: OPAR expr CPAR //parExpr
| (INT | FLOAT) //numberAtom
| (TRUE | FALSE) //booleanAtom
| ID //idAtom
| STRING //stringAtom
| NULL //nullAtom
;
有人可以解释为什么这种定义语法的方式也有效吗?是因为antlr的一些特殊处理还是其他类型的语法定义?
下面是为语法定义的操作符和ids:
OR : '||';
AND : '&&';
EQ : '==';
NEQ : '!=';
GT : '>';
LT : '<';
GTEQ : '>=';
LTEQ : '<=';
NOT : '!';
OPAR : '(';
CPAR : ')';
TRUE : 'true';
FALSE : 'false';
NULL : 'null';
ID
: [a-zA-Z_] [a-zA-Z_0-9]*
;
INT
: [0-9]+
;
FLOAT
: [0-9]+ '.' [0-9]*
| '.' [0-9]+
;
STRING
: '"' (~["\r\n] | '""')* '"'
;
COMMENT
: '//' ~[\r\n]* -> skip
;
SPACE
: [ \t\r\n] -> skip
;
OTHER
: .
;
这是 ANTLR v4 特有的。
在幕后,像这样的规则将被重写为等同于您在左递归消除步骤中手动完成的内容。 ANTLR 这样做是为了方便,因为 LL 文法不能包含左递归规则,因为将这种规则直接转换为解析器代码会在代码中产生无限递归(无条件调用自身的函数)。
the docs page about left-recursion 中有更多信息和转换示例。
我对编译器理论比较陌生,我只是想创建一个语法来解析一些比较,以便稍后对其进行评估。我发现 antlr 是指定语法的强大工具。根据我在理论中学到的知识,我知道优先级较高的运算符必须比优先级较低的运算符在更深的层次上声明。此外,如果我希望某些规则保持关联,我知道我必须将递归性设置为规则的左侧。知道我已经创建了一个基本语法来使用 &&、||、!=、==、<、>、<=、>=、(,) 和 !
start
: orExpr
;
orExpr
: orExpr OR andExpr
| andExpr
;
andExpr
: andExpr AND eqNotEqExpr
| eqNotEqExpr
;
eqNotEqExpr
: eqNotEqExpr NEQ compExpr
| eqNotEqExpr EQ compExpr
| compExpr
;
compExpr
: compExpr LT compExpr
| compExpr GT compExpr
| compExpr LTEQ compExpr
| compExpr GTEQ compExpr
| notExpr
;
notExpr
: NOT notExpr
| parExpr
;
parExpr
: OPAR orExpr CPAR
| id
;
id
: INT
| FLOAT
| TRUE
| FALSE
| ID
| STRING
| NULL
;
但是在互联网上搜索我发现了一种不同的方式来指定上述语法,它不遵循我提到的关于运算符优先级和左结合性的上述规则:
start
: expr
;
expr
: NOT expr //notExpr
| expr op=(LTEQ | GTEQ | LT | GT) expr //relationalExpr
| expr op=(EQ | NEQ) expr //equalityExpr
| expr AND expr //andExpr
| expr OR expr //orExpr
| atom //atomExpr
;
atom
: OPAR expr CPAR //parExpr
| (INT | FLOAT) //numberAtom
| (TRUE | FALSE) //booleanAtom
| ID //idAtom
| STRING //stringAtom
| NULL //nullAtom
;
有人可以解释为什么这种定义语法的方式也有效吗?是因为antlr的一些特殊处理还是其他类型的语法定义?
下面是为语法定义的操作符和ids:
OR : '||';
AND : '&&';
EQ : '==';
NEQ : '!=';
GT : '>';
LT : '<';
GTEQ : '>=';
LTEQ : '<=';
NOT : '!';
OPAR : '(';
CPAR : ')';
TRUE : 'true';
FALSE : 'false';
NULL : 'null';
ID
: [a-zA-Z_] [a-zA-Z_0-9]*
;
INT
: [0-9]+
;
FLOAT
: [0-9]+ '.' [0-9]*
| '.' [0-9]+
;
STRING
: '"' (~["\r\n] | '""')* '"'
;
COMMENT
: '//' ~[\r\n]* -> skip
;
SPACE
: [ \t\r\n] -> skip
;
OTHER
: .
;
这是 ANTLR v4 特有的。
在幕后,像这样的规则将被重写为等同于您在左递归消除步骤中手动完成的内容。 ANTLR 这样做是为了方便,因为 LL 文法不能包含左递归规则,因为将这种规则直接转换为解析器代码会在代码中产生无限递归(无条件调用自身的函数)。
the docs page about left-recursion 中有更多信息和转换示例。