是否可以使用侦听器而不是java中的访问者来评估antlr4中的IF
语句?如果是这样,你能建议怎么做?
我正在尝试为我的语言翻译。我已经使用生成的antlr监听器来实现它。我已经完成了对表达式的语义分析和评估,现在我不知道如何评估IF
,WHILE
,FOR
等函数调用。
我在antlr4中的语法不包括词汇规则:
grammar CodeCraftGrammar;
@header{
package gen;
}
program
: constantStatement* mainFunction functionDeclaration* EOF
;
constantStatement
: ABSOLUTE dataType ID ASSIGN expression SEMI
;
variableDeclaration
: dataType ID
;
dataType
: INT
| FLOAT
| CHAR
| STRING
| BOOLEAN
;
functionDeclaration
: returnType ID parameterList block
;
returnType
: dataType #returnDataType
| DARKNESS #returnDarkness
;
parameterList
: LPAREN parameter? (COMMA parameter)* RPAREN
;
parameter
: dataType ID
;
block
: LBRACE statement* RBRACE
;
mainFunction
: DARKNESS MINE parameterList block
;
statement
: block #blockStatement
| variableDeclaration SEMI #varDec
| assignmentStatement SEMI #assign
| functionCallStatement SEMI #funcCall
| ifStatement #if
| whileStatement #while
| doWhileStatement #dowhile
| forStatement #for
| returnStatement #return
| CHOKE SEMI #choke
;
assignmentStatement
: ID ASSIGN expression
;
functionCallStatement
: ID actualParameters #funcCallID
| PRINT actualParameters #funcCallPrint
| PRINTLN actualParameters #funcCallPrintln
;
actualParameters
: LPAREN expression? (COMMA expression)* RPAREN
;
ifStatement
: WETHER condition block OTHERWISE block #ifelse
| WETHER condition block #ifonly
;
condition
: LPAREN expression RPAREN
;
whileStatement
: UNTIL condition block
;
doWhileStatement
: EXECUTE block UNTIL condition SEMI
;
forStatement
: AS LPAREN assignmentStatement SEMI expression SEMI assignmentStatement RPAREN block
;
returnStatement
: REPLY expression SEMI
;
expression
: '!' expression #bangExpr
| '(' expression ')' #parensExpr
| expression ('*'|'/'|'%') expression #multdivmodExpr
| expression ('+'|'-') expression #addminusExpr
| expression ('>='|'<='|'<'|'>') expression #relationalExpr
| expression ('=='|'!=') expression #equalityExpr
| expression '&&' expression #andExpr
| expression '||' expression #orExpr
| IntegerLiteral #intExpr
| BooleanLiteral #boolExpr
| FloatingPointLiteral #floatExpr
| StringLiteral #stringExpr
| CharacterLiteral #charExpr
| ID actualParameters #funcCallExpr
| ID #idExpr
| NULL #nullExpr
;
这是口译员开始的地方:
public Main(String code, String[] args,JTextArea ta)throws Exception {
this.ta =ta;
String inputFile = "src/sample_code.cc";
InputStream is=null;
if ( inputFile!=null ) {
is = new FileInputStream(inputFile);
}
//is = new StringBufferInputStream(code);
ANTLRInputStream input = new ANTLRInputStream(is);
CodeCraftGrammarLexer lexer = new CodeCraftGrammarLexer(input);
CodeCraftGrammarParser parser = new CodeCraftGrammarParser(new CommonTokenStream(lexer));
parser.setBuildParseTree(true);
ParseTree tree = parser.program();
List<String> ruleNames = Arrays.asList(parser.getRuleNames());
TreeViewer tv = new TreeViewer(ruleNames, tree);
ParseTreeWalker walker = new ParseTreeWalker();
FirstPass def = new FirstPass();
walker.walk(def, tree);
// create next phase and feed symbol table info from define to reference phase
SecondPass ref = new SecondPass(def.globals, def.scopes);
walker.walk(ref, tree);
}
这是解析树中的第一个传递,它首先定义所有变量和函数:
public class FirstPass extends CodeCraftGrammarBaseListener{
ParseTreeProperty<Scope> scopes = new ParseTreeProperty<Scope>();
GlobalScope globals;
Scope currentScope; // define symbols in this scope
void saveScope(ParserRuleContext ctx, Scope s) { scopes.put(ctx, s); }
public FirstPass(){
}
public void enterProgram(@NotNull ProgramContext ctx) {
globals = new GlobalScope(null);
currentScope = globals;
}
public void exitProgram(@NotNull ProgramContext ctx) {
Main.displayScope(globals);
}
public void enterFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
String name = ctx.ID().getText();
int typeTokenType = ctx.returnType().start.getType(); //UNSURE
Symbol.Type type = Main.getType(typeTokenType);
// push new scope by making new one that points to enclosing scope
FunctionSymbol function = new FunctionSymbol(name, type, currentScope);
GlobalScope temp = (GlobalScope) currentScope;
if(temp.symbols.containsKey(function.name)){
//multiple function declaration in same global scope
Main.error(ctx.ID().getSymbol(), "Function already declared: "+name);
}//UNSURE should i let it continue saving in symbol table
currentScope.define(function); // Define function in current scope
saveScope(ctx, function); // Push: set function's parent to current
currentScope = function; // Current scope is now function scope
if(currentScope.getClass()==FunctionSymbol.class)
currentScope = (FunctionSymbol)currentScope;
}
public void enterMainFunction(@NotNull MainFunctionContext ctx) {
String name = ctx.MINE().getText();
int typeTokenType = ctx.DARKNESS().getSymbol().getType(); //UNSURE
Symbol.Type type = Main.getType(typeTokenType);
// push new scope by making new one that points to enclosing scope
FunctionSymbol function = new FunctionSymbol(name, type, currentScope);
GlobalScope temp = (GlobalScope) currentScope;
if(temp.symbols.containsKey(function.name)){
//multiple function declaration in same global scope
Main.error(ctx.MINE().getSymbol(), "Main already declared: "+name);
}//UNSURE should i let it continue saving in symbol table
currentScope.define(function); // Define function in current scope
saveScope(ctx, function); // Push: set function's parent to current
currentScope = function; // Current scope is now function scope
if(currentScope.getClass()==FunctionSymbol.class)
currentScope = (FunctionSymbol)currentScope;
}
public void exitFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
Main.displayScope(currentScope);
currentScope = currentScope.getEnclosingScope(); // pop scope
if(currentScope.getClass()==GlobalScope.class)
currentScope = (GlobalScope)currentScope;
}
public void exitMainFunction(@NotNull MainFunctionContext ctx) {
Main.displayScope(currentScope);
currentScope = currentScope.getEnclosingScope(); // pop scope
if(currentScope.getClass()==GlobalScope.class)
currentScope = (GlobalScope)currentScope;
}
public void enterBlock(CodeCraftGrammarParser.BlockContext ctx) {
// push new local scope
currentScope = new LocalScope(currentScope);
currentScope = (LocalScope)currentScope;
saveScope(ctx, currentScope);
}
public void exitBlock(CodeCraftGrammarParser.BlockContext ctx) {
Main.displayScope(currentScope);
currentScope = currentScope.getEnclosingScope(); // pop scope
if(currentScope.getClass()==FunctionSymbol.class)
currentScope = (FunctionSymbol)currentScope;
}
public void exitParameter(@NotNull ParameterContext ctx) {
FunctionSymbol temp = (FunctionSymbol) currentScope;
String name = ctx.ID().getText();
if(temp.arguments.containsKey(name)){
//multiple function declaration in same global scope
Main.error(ctx.ID().getSymbol(), "Parameter already declared: "+name);
}
defineVar(ctx.dataType(), ctx.ID().getSymbol(),false);
}
public void exitVariableDeclaration(@NotNull VariableDeclarationContext ctx) {
LocalScope temp = (LocalScope) currentScope;
String name = ctx.ID().getText();
if(temp.symbols.containsKey(name)){
//multiple function declaration in same global scope
Main.error(ctx.ID().getSymbol(), "Variable already declared: "+name);
}
defineVar(ctx.dataType(), ctx.ID().getSymbol(),false);
}
public void exitConstantStatement(@NotNull ConstantStatementContext ctx) {
GlobalScope temp = (GlobalScope) currentScope;
ConstantStatementContext ctx2 = ctx;
String name = ctx2.ID().getText();
if(temp.symbols.containsKey(name)){
//multiple function declaration in same global scope
Main.error(ctx2.ID().getSymbol(), "Constant already declared: "+name);
}
defineVar(ctx2.dataType(), ctx2.ID().getSymbol(),true);
}
void defineVar(CodeCraftGrammarParser.DataTypeContext typeCtx, Token nameToken, Boolean isConstant) {
int typeTokenType = typeCtx.start.getType(); //UNSURE
Symbol.Type type = Main.getType(typeTokenType);
VariableSymbol var = new VariableSymbol(nameToken.getText(), type, isConstant);
currentScope.define(var); // Define symbol in current scope
}
}
第二遍:
public class SecondPass extends CodeCraftGrammarBaseListener{
ParseTreeProperty<Scope> scopes;
GlobalScope globals;
Scope currentScope; // resolve symbols starting in this scope
JTextArea ta;
Stack<Symbol> stack = new Stack<Symbol>();
Symbol op1,op2,ans;
public SecondPass(GlobalScope globals, ParseTreeProperty<Scope> scopes) {
this.scopes = scopes;
this.globals = globals;
}
public void enterProgram(@NotNull ProgramContext ctx) {
currentScope = globals;
}
public void enterFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
currentScope = scopes.get(ctx);
}
public void exitFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
currentScope = currentScope.getEnclosingScope();
}
public void enterBlock(@NotNull BlockContext ctx) {
currentScope = scopes.get(ctx);
}
public void exitBlock(@NotNull BlockContext ctx) {
currentScope = currentScope.getEnclosingScope();
}
public void exitIf(@NotNull IfContext ctx) {
}
public void exitFuncCallID(@NotNull FuncCallIDContext ctx) {
String funcName = ctx.ID().getText();
Symbol meth = currentScope.resolve(funcName);
if ( meth==null ) {
Main.error(ctx.ID().getSymbol(), "no such function: "+funcName);
}
if ( meth instanceof VariableSymbol ) {
Main.error(ctx.ID().getSymbol(), funcName+" is not a function");
}
}
public void exitAssignmentStatement(AssignmentStatementContext ctx) {
String name = ctx.ID().getSymbol().getText();
Symbol var = currentScope.resolve(name);
if ( var==null ) {
Main.error(ctx.ID().getSymbol(), "no such variable: "+name);
}
if ( var instanceof FunctionSymbol ) {
Main.error(ctx.ID().getSymbol(), name+" is not a variable");
}
Symbol x = stack.pop();
System.out.println("==\n::assign value"+x.value + " assign type:" + x.type.toString());
if(var.type == x.type){
currentScope.resolve(name).value = x.value;
System.out.println("assignment name:"+name +" value: "+currentScope.resolve(name).value+" type:"+currentScope.resolve(name).type+"===\n");
}else if (var.type == Type.tFLOAT && x.type== Type.tINT){
currentScope.resolve(name).value = x.asFloat();
System.out.println("assignment name:"+name +" value: "+currentScope.resolve(name).value+" type:"+currentScope.resolve(name).type+"===\n");
}else{
}
}
public void exitFuncCallExpr(@NotNull FuncCallExprContext ctx) {
String funcName = ctx.ID().getText();
Symbol meth = currentScope.resolve(funcName);
if ( meth==null ) {
Main.error(ctx.ID().getSymbol(), "no such function: "+funcName);
}
if ( meth instanceof VariableSymbol ) {
Main.error(ctx.ID().getSymbol(), funcName+" is not a function");
}
//#WHAT THE HECK
}
public void exitBangExpr(@NotNull BangExprContext ctx) {
Symbol op1 = stack.pop();
Symbol ans=null;
String operator = ctx.getChild(0).getText();
if(op1.isBoolean()){
if (operator.equals("!")){
ans = new Symbol(Type.tBOOLEAN, !op1.asBoolean());
}
stack.push(ans);
}else{
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitOrExpr(@NotNull OrExprContext ctx) {
Symbol op1 = stack.pop();
Symbol op2 = stack.pop();
Symbol ans=null;
String operator = ctx.getChild(1).getText();
if(op1.isBoolean()&&op2.isBoolean()){
if (operator.equals("||")){
ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() || op1.asBoolean());
}
stack.push(ans);
}else{
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitAndExpr(@NotNull AndExprContext ctx) {
Symbol op1 = stack.pop();
Symbol op2 = stack.pop();
Symbol ans=null;
String operator = ctx.getChild(1).getText();
if(op1.isBoolean()&&op2.isBoolean()){
if (operator.equals("&&")){
ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() && op1.asBoolean());
}
stack.push(ans);
}else{
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitEqualityExpr(@NotNull EqualityExprContext ctx) {
Symbol op1 = stack.pop();
Symbol op2 = stack.pop();
Symbol ans=null;
String operator = ctx.getChild(1).getText();
if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
if (operator.equals("==")){
ans = new Symbol(Type.tBOOLEAN, op2.asFloat() == op1.asFloat());
}else if (operator.equals("!=")){
ans = new Symbol(Type.tBOOLEAN, op2.asFloat() != op1.asFloat());
}
stack.push(ans);
}else if(op1.isBoolean()&&op2.isBoolean()){
if (operator.equals("==")){
ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() == op1.asBoolean());
}else if (operator.equals("!=")){
ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() != op1.asBoolean());
}
stack.push(ans);
}else if(op1.isString()&&op2.isString()){
if (operator.equals("==")){
ans = new Symbol(Type.tBOOLEAN, op2.asString() == op1.asString());
}else if (operator.equals("!=")){
ans = new Symbol(Type.tBOOLEAN, op2.asString() != op1.asString());
}
stack.push(ans);
}else if(op1.isChar()&&op2.isChar()){
if (operator.equals("==")){
ans = new Symbol(Type.tBOOLEAN, op2.asChar() == op1.asChar());
}else if (operator.equals("!=")){
ans = new Symbol(Type.tBOOLEAN, op2.asChar() != op1.asChar());
}
stack.push(ans);
}else{
//error expression type mismatch
//The operator - is undefined for the argument type(s) java.lang.String, java.lang.String
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitRelationalExpr(@NotNull RelationalExprContext ctx) {
Symbol op1 = stack.pop();
Symbol op2 = stack.pop();
Symbol ans=null;
String operator = ctx.getChild(1).getText();
if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
if (operator.equals(">")){
ans = new Symbol(Type.tBOOLEAN, op2.asFloat() > op1.asFloat());
}else if (operator.equals("<")){
ans = new Symbol(Type.tBOOLEAN, op2.asFloat() < op1.asFloat());
}else if (operator.equals(">=")){
ans = new Symbol(Type.tBOOLEAN, op2.asFloat() >= op1.asFloat());
}else if (operator.equals("<=")){
ans = new Symbol(Type.tBOOLEAN, op2.asFloat() <= op1.asFloat());
}
stack.push(ans);
}else{
//error expression type mismatch
//The operator - is undefined for the argument type(s) java.lang.String, java.lang.String
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitMultdivmodExpr(MultdivmodExprContext ctx) {
Symbol op1 = stack.pop();
Symbol op2 = stack.pop();
Symbol ans=null;
String operator = ctx.getChild(1).getText();
if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
if(op1.asFloat()==0 && (operator.equals("/")||operator.equals("%"))){
//error div/mod by zero
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "Arithmetic Error: " + operator +" by zero";
Main.semanticError(tn.getSymbol(),msg);
}else {
if(op1.isFloat()||op2.isFloat()){ //push as float
if (operator.equals("*")){
ans = new Symbol(Type.tFLOAT, op2.asFloat() * op1.asFloat());
}else if(operator.equals("/")){
ans = new Symbol(Type.tFLOAT, op2.asFloat() / op1.asFloat());
}else if(operator.equals("%")){
ans = new Symbol(Type.tFLOAT, op2.asFloat() % op1.asFloat());
}
}else{ //push as int
if (operator.equals("*")){
ans = new Symbol(Type.tINT, op2.asInt() * op1.asInt());
}else if(operator.equals("/")){
ans = new Symbol(Type.tINT, op2.asInt() / op1.asInt());
}else if(operator.equals("%")){
ans = new Symbol(Type.tINT, op2.asInt() % op1.asInt());
}
}
stack.push(ans);
}
}else{
//error expression type mismatch
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitAddminusExpr(AddminusExprContext ctx) {
Symbol op1 = stack.pop();
Symbol op2 = stack.pop();
Symbol ans;
String operator = ctx.getChild(1).getText();
if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
if(op1.isFloat()||op2.isFloat()){ //push as float
if (operator.equals("-")){
ans = new Symbol(Type.tFLOAT, op2.asFloat() - op1.asFloat());
}else{
ans = new Symbol(Type.tFLOAT, op2.asFloat() + op1.asFloat());
}
}else{ //push as int
if (operator.equals("-")){
ans = new Symbol(Type.tINT, op2.asInt() - op1.asInt());
}
else{
ans = new Symbol(Type.tINT, op2.asInt() + op1.asInt() );
}
}
stack.push(ans);
}else if(op1.isString() && op2.isString() && operator.equals("+")){
ans = new Symbol(Type.tSTRING, op2.asString() + op1.asString());
stack.push(ans);
}else{
//error expression type mismatch
//The operator - is undefined for the argument type(s) java.lang.String, java.lang.String
TerminalNode tn = (TerminalNode) ctx.getChild(1);
String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
Main.semanticError(tn.getSymbol(),msg);
}
}
public void exitNullExpr(NullExprContext ctx) {
Symbol s = new Symbol(Type.tNULL,null);
stack.push(s);
}
public void exitIdExpr(@NotNull CodeCraftGrammarParser.IdExprContext ctx) {
String name = ctx.ID().getSymbol().getText();
Symbol var = currentScope.resolve(name);
if ( var==null ) {
Main.semanticError(ctx.ID().getSymbol(), "no such variable: "+name);
}else if ( var instanceof FunctionSymbol ) {
Main.semanticError(ctx.ID().getSymbol(), name+" is not a variable");
}else{
stack.push(var);
}
}
public void exitIntExpr(IntExprContext ctx) {
String valueInString = ctx.IntegerLiteral().getSymbol().getText();
Integer valueInInteger = Integer.valueOf(valueInString);
Symbol s = new Symbol(Type.tINT,valueInInteger);
stack.push(s);
}
public void exitFloatExpr(FloatExprContext ctx) {
String valueInString = ctx.FloatingPointLiteral().getSymbol().getText();
Float valueInFloat = Float.valueOf(valueInString);
Symbol s = new Symbol(Type.tFLOAT,valueInFloat);
stack.push(s);
}
public void exitBoolExpr(BoolExprContext ctx) {
String value = ctx.BooleanLiteral().getSymbol().getText();
Symbol s = null;
if("true".equals(value)){
s = new Symbol(Type.tBOOLEAN,true);
}else if("false".equals(value)){
s = new Symbol(Type.tBOOLEAN,false);
}
stack.push(s);
}
public void exitStringExpr(StringExprContext ctx) {
String value = ctx.StringLiteral().getSymbol().getText();
Symbol s;
if(value.length()==2){ //String is blank
s = new Symbol(Type.tSTRING,"");
}else{
s = new Symbol(Type.tSTRING,value.substring(1, value.length()-1));
}
stack.push(s);
}
public void exitCharExpr(CharExprContext ctx) {
String value = ctx.CharacterLiteral().getSymbol().getText();
Symbol s = new Symbol(Type.tCHAR,value.charAt(1));
stack.push(s);
}
}
答案 0 :(得分:3)
使用侦听器接口评估IF语句将很困难,与侦听器接口一样,您将由Antlr树walker驱动,它以其所有者顺序传递AST树。但是,为了评估IF语句,您需要根据条件语句的评估结果来控制AST或部分AST的评估顺序。
我认为访问者界面更适合评估IF,For / While和函数调用。