While loop 使用ANTLR同时执行while和while
前面我创建了询问如何使用ANTLR 4创建if/else语句。我得到了一个很好的答案,它也展示了如何做while循环。我已经在我的语言中实现了这一点,现在我正试图使用几乎相同的原则进行do-while循环 while循环的语法如下所示:While loop 使用ANTLR同时执行while和while,while-loop,antlr,do-while,antlr4,While Loop,Antlr,Do While,Antlr4,前面我创建了询问如何使用ANTLR 4创建if/else语句。我得到了一个很好的答案,它也展示了如何做while循环。我已经在我的语言中实现了这一点,现在我正试图使用几乎相同的原则进行do-while循环 while循环的语法如下所示: count is 0 while count is less than 10 count+ if count not equals 10 write " " + count + ": Getting there..." else if cou
count is 0
while count is less than 10
count+
if count not equals 10
write " " + count + ": Getting there..."
else if count equals 10
write count + ": The end!"
end if
end while
count is 0
do
count+
write "count is " + count
if count equals 10
write "The end!"
end if
while count is less than 10
这就是我想做的while循环:
count is 0
while count is less than 10
count+
if count not equals 10
write " " + count + ": Getting there..."
else if count equals 10
write count + ": The end!"
end if
end while
count is 0
do
count+
write "count is " + count
if count equals 10
write "The end!"
end if
while count is less than 10
我已经测试过了,但是它们都能工作,不是同时工作的。下面是我的语法(很抱歉发布了所有内容,但我认为这是必要的)
如果我的WHILE
和END\u WHILE
标记高于我的DO\u WHILE
和DO\u WHILE\u条件
标记,则WHILE循环工作。但是,如果我在do while循环工作时切换它们。如果我将DO\u WHILE\u条件
标记更改为WHILE以外的任何内容,那么这两个标记都可以工作
我是否可以让它们都使用当前语法?我明白这可能是一个问题,因为我在很多事情上使用同一个关键字,但我希望有办法做到这一点
//////////////////////////////////
// PARSER
//////////////////////////////////
program
: block EOF
;
block
: (statement (NEW_LINE+ | EOF))*
;
statement
: assignment
| if_statement
| while_statement
| until_statement
| do_while_statement
| write
;
assignment
: ID ASSIGN expression # expressionAssignment
| ID PLUS # incrementAssignment
| ID MINUS # decrementAssignment
;
if_statement
: IF condition_block (ELSE_IF condition_block)* (ELSE NEW_LINE statement_block)? END_IF
;
condition_block
: expression NEW_LINE statement_block
;
statement_block
: block
;
while_statement
: WHILE expression NEW_LINE statement_block END_WHILE
;
until_statement
: UNTIL expression NEW_LINE statement_block END_UNTIL
;
do_while_statement
: DO_WHILE NEW_LINE statement_block DO_WHILE_CONDITION expression
;
expression
: atom # atomExpression
| expression PLUS expression # plusExpression
| expression MINUS expression # minusExpression
| expression MULTIPLY expression # multiplicationExpression
| expression DIVIDE expression # divisionExpression
| expression PLUS # incrementExpression
| expression MINUS # decrementExpression
| expression AND expression # andExpression
| expression OR expression # orExpression
| expression EQUALS expression # equalityExpression
| expression NOT_EQUALS expression # notEqualityExpression
| expression LESS_THAN expression # lessThanExpression
| expression NOT_LESS_THAN expression # notLessThanExpression
| expression GREATER_THAN expression # greaterThanExpression
| expression NOT_GREATER_THAN expression # notGreaterThanExpression
| expression GREATER_THAN_OR_EQUAL expression # greaterThanOrEqualExpression
| expression LESS_THAN_OR_EQUAL expression # lessThanOrEqualExpression
;
atom
: INT # integerAtom
| FLOAT # floatAtom
| BOOLEAN # boolAtom
| ID # idAtom
| STRING # stringAtom
| OPEN_PAR expression CLOSE_PAR # expressionAtom
;
write
: WRITE expression
;
//////////////////////////////////
// LEXER
//////////////////////////////////
PLUS : '+';
MINUS : '-';
MULTIPLY : '*';
DIVIDE : '/';
ASSIGN : 'is';
OPEN_CURLY : '{';
CLOSE_CURLY : '}';
OPEN_PAR : '(';
CLOSE_PAR : ')';
COLON : ':';
NEW_LINE : '\r'? '\n';
IF : 'if';
ELSE_IF : 'else if';
ELSE : 'else';
END_IF : 'end if';
WHILE : 'while';
END_WHILE : 'end while';
UNTIL : 'until';
END_UNTIL : 'end until';
DO_WHILE : 'do';
DO_WHILE_CONDITION : 'while';
EQUALS : 'equals';
NOT_EQUALS : 'not equals';
LESS_THAN : 'is less than';
NOT_LESS_THAN : 'is not less than';
GREATER_THAN : 'is greater than';
NOT_GREATER_THAN : 'is not greater than';
GREATER_THAN_OR_EQUAL : 'is greater than or equals';
LESS_THAN_OR_EQUAL : 'is less than or equals';
WRITE : 'write';
AND : 'and';
OR : 'or';
NOT : 'not';
BOOLEAN
: 'TRUE' | 'true' | 'YES' | 'yes'
| 'FALSE' | 'false' | 'NO' | 'no'
;
INT
: (PLUS | MINUS)? NUMBER+
;
FLOAT
: (PLUS | MINUS)? NUMBER+ ('.' | ',') (NUMBER+)?
| (PLUS | MINUS)? (NUMBER+)? ('.' | ',') NUMBER+
;
NUMBER
: '0'..'9'
;
STRING
: '"' ( '\\"' | ~["] )* '"'
;
ID
: ('a'..'z' | 'A'..'Z' | '0'..'9')+
;
WHITESPACE
: [ \t]+ -> skip
;
COMMENT
: ( ';;' .*? ';;' | ';' ~[\r\n]* ) -> skip
;
在创建标记时,lexer没有考虑解析器在某一点可能需要什么。检查此描述规则的问答(适用于v3和v4): 这意味着在您的情况下,规则
DO\u WHILE\u条件
:
WHILE : 'while';
...
DO_WHILE_CONDITION : 'while';
永远不会匹配
除此之外,用空格将关键字“粘合”在一起通常不是一个好主意。当输入为代码>“Endif”< /C> >(2个空格)时,请考虑。最好创建两个标记:一个END
和一个IF
,并在解析器规则中使用它们
试着这样做:
program
: block
;
block
: NEW_LINE* (statement (NEW_LINE+ | EOF))*
;
statement
: assignment
| if_statement
| while_statement
| until_statement
| do_while_statement
| write
;
assignment
: ID IS expression # expressionAssignment
| ID PLUS # incrementAssignment
| ID MINUS # decrementAssignment
;
if_statement
: IF condition_block (ELSE IF condition_block)* (ELSE NEW_LINE statement_block)? END IF
;
condition_block
: expression NEW_LINE statement_block
;
statement_block
: block
;
while_statement
: WHILE expression NEW_LINE statement_block END WHILE
;
until_statement
: UNTIL expression NEW_LINE statement_block END UNTIL
;
do_while_statement
: DO NEW_LINE statement_block WHILE expression
;
// Added unary expressions instead of combining them in the lexer.
expression
: atom # atomExpression
| MINUS expression # unaryMinusExpression
| PLUS expression # unaryPlusExpression
| expression PLUS expression # plusExpression
| expression MINUS expression # minusExpression
| expression MULTIPLY expression # multiplicationExpression
| expression DIVIDE expression # divisionExpression
| expression PLUS # incrementExpression
| expression MINUS # decrementExpression
| expression AND expression # andExpression
| expression OR expression # orExpression
| expression EQUALS expression # equalityExpression
| expression NOT EQUALS expression # notEqualityExpression
| expression IS LESS THAN expression # lessThanExpression
| expression IS NOT LESS THAN expression # notLessThanExpression
| expression IS GREATER THAN expression # greaterThanExpression
| expression IS NOT GREATER THAN expression # notGreaterThanExpression
| expression IS GREATER THAN OR EQUALS expression # greaterThanOrEqualExpression
| expression IS LESS THAN OR EQUALS expression # lessThanOrEqualExpression
;
atom
: INT # integerAtom
| FLOAT # floatAtom
| bool # boolAtom
| ID # idAtom
| STRING # stringAtom
| OPEN_PAR expression CLOSE_PAR # expressionAtom
;
write
: WRITE expression
;
// By making this a parser rule, you needn't inspect the lexer rule
// to see if it's true or false.
bool
: TRUE
| FALSE
;
//////////////////////////////////
// LEXER
//////////////////////////////////
PLUS : '+';
MINUS : '-';
MULTIPLY : '*';
DIVIDE : '/';
OPEN_CURLY : '{';
CLOSE_CURLY : '}';
OPEN_PAR : '(';
CLOSE_PAR : ')';
COLON : ':';
NEW_LINE : '\r'? '\n';
IF : 'if';
ELSE : 'else';
END : 'end';
WHILE : 'while';
UNTIL : 'until';
DO : 'do';
EQUALS : 'equals';
NOT : 'not';
IS : 'is';
LESS : 'less';
THAN : 'than';
GREATER : 'greater';
WRITE : 'write';
AND : 'and';
OR : 'or';
TRUE : 'TRUE' | 'true' | 'YES' | 'yes';
FALSE : 'FALSE' | 'false' | 'NO' | 'no';
INT
: DIGIT+
;
// (DIGIT+)? is the same as: DIGIT*
FLOAT
: DIGIT+ [.,] DIGIT*
| DIGIT* [.,] DIGIT+
;
// If a rule can never become a token on its own (an INT will always
// be created instead of a DIGIT), mark it as a 'fragment'.
fragment DIGIT
: [0-9]
;
// Added support for escaped backslashes.
STRING
: '"' ( '\\"' | '\\\\' | ~["\\] )* '"'
;
// Can it start with a digit? Maybe this is better: [a-zA-Z] [a-zA-Z0-9]*
ID
: [a-zA-Z0-9]+
;
WHITESPACE
: [ \t]+ -> skip
;
COMMENT
: ( ';;' .*? ';;' | ';' ~[\r\n]* ) -> skip
;
这两个解析器在构造时都没有问题。还请注意,我对您的语法做了一些轻微的调整(请参阅内联注释)。一元表达式是一个重要的表达式,否则
1-2
将被标记为2INT
标记,在解析器中不能将其作为表达式进行匹配 谢谢!这就解决了问题,这确实是对语法的一些重大修正。我没有想到需要将使用空格的标记拆分为多个标记以及一元表达式。我真的很高兴你听到了。我不完全确定究竟是什么解决了while/do-while问题。它对两个表达式使用相同的标记吗?@simonbs,do while
解析器规则使用标记do\u while\u CONDITION
,但是这个标记永远不会由lexer创建,因为规则while
匹配相同的字符,并且它被放在do\u while\u CONDITION
之前。好的,我明白了。谢谢在旁注中,我发现规则必须是program:block;block:NEW_LINE*(statement(NEW_LINE+|EOF))*
拥有EOF
两次,如果输入没有以新行结束,它会期待它两次。@simonbs,我相应地调整了我的答案(在这种情况下,请随意编辑我的答案!)。