我使用ANTLR制作了自己的语言。 语法是完整的,但我想制作一个验证输入的树步行器。但这并不奏效。 当我(意外地)在树行走器中使用output = AST时,它编译时没有错误,但它不接受任何输入。 (它表示org.antlr.runtime.tree.CommonTree不能转换为tools.ANode)。 但我认为输出= AST不能用于树木行走者。但是,它不会编译。它给出了一个
internal error: /.../src/AwesomeChecker.g : java.lang.IllegalStateException: java.lang.NullPointerException
org.deved.antlride.runtime.AntlrErrorListener$DynamicToken.invokeMethod(AntlrErrorListener.java:59)
org.deved.antlride.runtime.AntlrErrorListener$DynamicToken.getLine(AntlrErrorListener.java:64)
org.deved.antlride.runtime.AntlrErrorListener.report(AntlrErrorListener.java:131)
org.deved.antlride.runtime.AntlrErrorListener.message(AntlrErrorListener.java:115)
org.deved.antlride.runtime.AntlrErrorListener.warning(AntlrErrorListener.java:99)
org.antlr.tool.ErrorManager.grammarWarning(ErrorManager.java:742)
org.antlr.tool.ErrorManager.grammarWarning(ErrorManager.java:757)
org.antlr.tool.Grammar.parseAndBuildAST(Grammar.java:655)
org.antlr.Tool.getRootGrammar(Tool.java:626)
org.antlr.Tool.process(Tool.java:459)
org.deved.antlride.runtime.Tool2.main(Tool2.java:24)
当我尝试使用命令行编译时,它说我应该添加output = AST。 我的第一个问题是编译器看到了一些只能在树解析器中使用的符号,但是我找不到任何非法的符号。符号。
你能帮帮我吗?
检查器的语法是:
//AwesomeChecker.g: ANTLR (context) checker voor Awesome++
tree grammar AwesomeChecker;
options
{
tokenVocab = Awesome; //import tokens from Awesome.tokens
ASTLabelType = ANode; //AST nodes are of type ANode
}
//Alter code generation so catch-clauses get replaced with this action.
//This disables ANTLR error handling: Exceptions are propagated upwards.
@rulecatch
{
catch (RecognitionException re)
{
throw re;
}
}
@header
{
import tools.*;
import java.util.List;
import java.util.ArrayList;
}
@members
{
//symbol table voor de identifiers
private SymbolTable ST = new SymbolTable();
//voor de AST types
private Checker checker = new Checker();
private void enter(ANode id, boolean isVar) throws AwesomeException {
try {
IdEntry ie = new IdEntry(id, isVar);
this.ST.enter(id.getText(), ie);
}
catch (SymbolTableException e) {
throw new AwesomeException(id, "Al gedeclareerd");
}
}
}
start
: program
;
program
@init { this.ST.openScope(); }
: ^(PROGRAM statement+) { this.ST.closeScope(); }
;
statement
: op=IDENTIFIER e=assignment_statement
{
checker.checkTypes($op, $e.start, op, checker.ANY_TYPE);
}
| output_stat
| input_stat
| if_statement[false]
| do_while_statement
| declaration
;
assignment_statement
: (op=BECOMES^ e=expr)+
{
op.setExprType($e.start.getExprType());
}
;
declaration
: ^(DECL t=type c=CONST? id=IDENTIFIER (e=expr)?)
{
boolean isVar = (c == null);
int type = id.setExprType($t.start.getExprType());
if(e == null) {
} else {
checker.checkType($e.start, type);
}
this.enter(id, isVar);
}
;
type
: t=BOOLEAN
{$t.setExprType(checker.BOOL_TYPE);}
| t=INTEGER
{$t.setExprType(checker.INT_TYPE);}
| t=CHAR
{$t.setExprType(checker.CHAR_TYPE);}
;
statements_block
@init { this.ST.openScope(); }
: statement*
{this.ST.closeScope();}
;
expr
: ^(op=COMPOUND (statement)* e=expr)
{
op.setExprType($e.start.getExprType());
}
| ^(op = (PLUS | MINUS | MULTIPLY) e1=expr e2=expr)
{
checker.checkTypes($e1.start, $e2.start, op, checker.INT_TYPE);
op.setExprType(checker.INT_TYPE);
}
| ^(op = (DIVIDE | MODULUS) e1=expr e2=expr)
{
checker.checkTypes($e1.start, $e2.start, op, checker.INT_TYPE);
if ($e2.text.equals("0"))
{
throw new AwesomeException($e2.start, "Cannot divide by zero");
}
op.setExprType(checker.INT_TYPE);
}
| ^(op = (SMALLER | SMALLEREQUAL | GREATEREQUAL | GREATER) e1=expr e2=expr)
{
checker.checkTypes($e1.start, $e2.start, op, checker.INT_TYPE);
op.setExprType(checker.BOOL_TYPE);
}
| ^(op = (EQUAL | NOTEQUAL) e1=expr e2=expr)
{
checker.checkTypes($e1.start, $e2.start, op, checker.ANY_TYPE);
op.setExprType(checker.BOOL_TYPE);
}
| ^(op = (AND | OR) e1=expr e2=expr)
{
checker.checkTypes($e1.start, $e2.start, op, checker.BOOL_TYPE);
op.setExprType(checker.BOOL_TYPE);
}
| ^(op = UNARYEXPR (PLUS | MINUS) e1=expr)
{
checker.checkType($e1.start, checker.INT_TYPE);
op.setExprType(checker.INT_TYPE);
}
| ^(op = UNARYEXPR NOTEQUAL e1=expr)
{
checker.checkType($e1.start, checker.BOOL_TYPE);
op.setExprType(checker.BOOL_TYPE);
}
;
input_stat
: ^(op=INPUT v=varlist)
{
int type = $v.start.getExprType();
op.setExprType(type);
}
;
output_stat
: ^(op=OUTPUT v=varlist)
{
int type = $v.start.getExprType();
op.setExprType(type);
}
;
if_statement[boolean isExpr]
: ^(op=IF cond=expr (statements_block|op1=operand) (ELSE (statements_block|op2=operand))?)
{
checker.checkType($cond.start, checker.BOOL_TYPE);
if(isExpr) {
int type = checker.checkTypes($op1.start, $op2.start, op, $op1.start.getExprType());
op.setExprType(type);
} else {
op.setExprType(checker.VOID_TYPE);
}
}
;
do_while_statement
: ^(op=DO statements_block WHILE cond=expr)
{
checker.checkType($cond.start, checker.BOOL_TYPE);
op.setExprType(checker.VOID_TYPE);
}
;
varlist
: expr (COMMA expr)*
;
operand
: IDENTIFIER
| literal
| expr
;
literal
: NUMBER
| CHARLITERAL
| boolliteral
;
boolliteral
: TRUE | FALSE
;
语法g是:
grammar Awesome;
options {
k=1; // LL(1) - do not use LL(*)
language=Java; // target language is Java (= default)
output=AST; // build an AST
}
tokens {
COLON = ':' ;
COMMA = ',' ;
SEMICOLON = ';' ;
LPAREN = '(' ;
RPAREN = ')' ;
LBRACKET = '{' ;
RBRACKET = '}' ;
// keyword for AST
DECL = 'decl' ;
UNARYEXPR = 'unexpr';
COMPOUND = 'compound';
ASSIGNMENT = 'ASSIGNMENT';
// operators
BECOMES = '=' ;
PLUS = '+' ;
MINUS = '-' ;
MULTIPLY = '*' ;
DIVIDE = '/' ;
MODULUS = '%' ;
EXCLAMATION = '!' ;
// comparators
AND = 'AND' ;
OR = 'OR' ;
SMALLER = '<' ;
SMALLEREQUAL = '<=' ;
GREATER = '>' ;
GREATEREQUAL = '>=' ;
EQUAL = '==' ;
NOTEQUAL = '!=' ;
// keywords
PROGRAM = 'program' ;
RETURN = 'return' ;
VAR = 'var' ;
CONST = 'const' ;
INPUT = 'input' ;
OUTPUT = 'output' ;
IF = 'if' ;
THEN = 'then' ;
ELSE = 'else' ;
DO = 'do' ;
WHILE = 'while' ;
// types
INTEGER = 'int' ;
BOOLEAN = 'bool' ;
CHAR = 'char' ;
STRING = 'string';
TRUE = 'true';
FALSE = 'false';
}
// Parser rules
start
: program
;
program
: (statement)+ EOF
-> ^(PROGRAM statement+)
;
statement
: IDENTIFIER assignment_statement SEMICOLON!
| output_stat SEMICOLON!
| input_stat SEMICOLON!
| if_statement
| do_while_statement
| declaration SEMICOLON!
;
declaration
: type CONST? IDENTIFIER (BECOMES expr)?
-> ^(DECL type CONST? IDENTIFIER (BECOMES expr)?)
;
type
: BOOLEAN
| INTEGER
| CHAR
| STRING
;
statements_block
: LBRACKET statement* RBRACKET
;
assignment_statement
: (BECOMES^ expr)+
;
expr
: expr_or
| expr_compound
| if_statement
;
expr_unary
: operand
| PLUS operand -> ^(UNARYEXPR PLUS operand)
| MINUS operand -> ^(UNARYEXPR MINUS operand)
| EXCLAMATION operand -> ^(UNARYEXPR EXCLAMATION operand)
;
expr_multiply
: expr_unary ((MULTIPLY | DIVIDE | MODULUS)^ expr_unary)*
;
expr_plus
: expr_multiply ((PLUS | MINUS)^ expr_multiply)*
;
expr_compare
: expr_plus ((SMALLER | SMALLEREQUAL | GREATEREQUAL | GREATER | EQUAL | NOTEQUAL)^ expr_plus)*
;
expr_and
: expr_compare (AND^ expr_compare)*
;
expr_or
: expr_and (OR^ expr_and)*
;
expr_compound
: LBRACKET (statement)* RETURN expr SEMICOLON RBRACKET
-> ^(COMPOUND (statement)* expr)
;
do_while_statement
: DO^ statements_block WHILE expr
;
if_statement
: IF^ expr (statements_block|operand) (ELSE (statements_block|operand))?
;
input_stat
: INPUT^ LPAREN! varlist RPAREN!
;
output_stat
: OUTPUT^ LPAREN! varlist RPAREN!
;
varlist
: expr (COMMA expr)*
;
operand
: IDENTIFIER
| literal
| LPAREN! expr RPAREN!
;
literal
: NUMBER
| CHARLITERAL
| boolliteral
;
boolliteral
: TRUE | FALSE
;
// Lexer rules
IDENTIFIER
: LETTER (LETTER | DIGIT)*
;
CHARLITERAL
: '\'' LETTER '\''
;
NUMBER
: DIGIT+
;
COMMENT
: '[' .* ']'
{ $channel=HIDDEN; }
;
WS
: (' ' | '\t' | '\f' | '\r' | '\n')+
{ $channel=HIDDEN; }
;
fragment DIGIT : ('0'..'9') ;
fragment LOWER : ('a'..'z') ;
fragment UPPER : ('A'..'Z') ;
fragment LETTER : LOWER | UPPER ;
// EOF
编辑: 我找到了
assignment_statement
: (op=BECOMES^ e=expr)+
是错误,应该是
assignment_statement
: (op=BECOMES e=expr)+
编译没有错误! :d 谢谢你的帮助!
答案 0 :(得分:1)
我找到了
assignment_statement
: (op=BECOMES^ e=expr)+
是错误,应该是
assignment_statement
: (op=BECOMES e=expr)+
我没有更改语法文件选项中的任何内容。
现在编译没有错误! :D谢谢你的帮助!
答案 1 :(得分:0)
但我认为
output=AST
不能在树木行走者中使用。
当然可以。这个想法是你的第一个语法将输入文本转换为节点树,然后树语法执行其他操作。如果你正在编写一个编译器,那么大概是树步行器介于解析和代码生成阶段之间。您的输出类型必须是AST,以便该过程的下一阶段可以完成它的工作......即使您实际上没有对树进行任何更改或对其执行任何其他操作。
你的问题是树语法中的这一行:
ASTLabelType = ANode
在树语法中,它期望传入的AST具有该类型的节点,但是您的第一个语法不会创建该类型的节点。它创建默认的CommonTree节点。所以只需在第一个语法中设置相同的行。
即使在官方参考书中,我也没有看到很多关于ASTLabelType
的文档,但是在antlr wiki的"Tree construction" page底部附近有一些关于自定义节点类型的注释。