Homework 3
This commit is contained in:
parent
bf60a078d7
commit
0afc86ceeb
129 changed files with 3163 additions and 4316 deletions
|
@ -10,6 +10,11 @@ public class Config {
|
|||
MACOSX
|
||||
}
|
||||
|
||||
/**
|
||||
* What kind of system we are on
|
||||
*/
|
||||
public static final SystemKind systemKind;
|
||||
|
||||
/**
|
||||
* Defines the extension used for assembler files on this platform.
|
||||
* Currently always {@code .s}.
|
||||
|
@ -79,9 +84,11 @@ public class Config {
|
|||
public static final String JAVA_EXE;
|
||||
|
||||
static {
|
||||
|
||||
final String os = System.getProperty("os.name").toLowerCase();
|
||||
|
||||
if(os.contains("windows") || os.contains("nt")) {
|
||||
systemKind = SystemKind.WINDOWS;
|
||||
BINARYEXT = ".exe";
|
||||
MAIN = "_main";
|
||||
PRINTF = "_printf";
|
||||
|
@ -101,6 +108,7 @@ public class Config {
|
|||
COMMENT_SEP = "#";
|
||||
}
|
||||
else if(os.contains("mac os x") || os.contains("darwin")) {
|
||||
systemKind = SystemKind.MACOSX;
|
||||
BINARYEXT = ".bin";
|
||||
MAIN = "_main";
|
||||
PRINTF = "_printf";
|
||||
|
@ -118,6 +126,7 @@ public class Config {
|
|||
COMMENT_SEP = "#";
|
||||
}
|
||||
else {
|
||||
systemKind = SystemKind.LINUX;
|
||||
BINARYEXT = ".bin";
|
||||
MAIN = "main";
|
||||
PRINTF = "printf";
|
||||
|
|
|
@ -19,7 +19,10 @@ import cd.frontend.parser.JavaliLexer;
|
|||
import cd.frontend.parser.JavaliParser;
|
||||
import cd.frontend.parser.JavaliParser.UnitContext;
|
||||
import cd.frontend.parser.ParseFailure;
|
||||
import cd.frontend.semantic.SemanticAnalyzer;
|
||||
import cd.ir.Ast.ClassDecl;
|
||||
import cd.ir.Symbol;
|
||||
import cd.ir.Symbol.TypeSymbol;
|
||||
import cd.util.debug.AstDump;
|
||||
|
||||
/**
|
||||
|
@ -34,9 +37,15 @@ public class Main {
|
|||
// Set to non-null to write debug info out
|
||||
public Writer debug = null;
|
||||
|
||||
// Set to non-null to write dump of control flow graph
|
||||
// Set to non-null to write dump of control flow graph (Advanced Compiler Design)
|
||||
public File cfgdumpbase;
|
||||
|
||||
/** Symbol for the Main type */
|
||||
public Symbol.ClassSymbol mainType;
|
||||
|
||||
/** List of all type symbols, used by code generator. */
|
||||
public List<TypeSymbol> allTypeSymbols;
|
||||
|
||||
public void debug(String format, Object... args) {
|
||||
if (debug != null) {
|
||||
String result = String.format(format, args);
|
||||
|
@ -62,6 +71,9 @@ public class Main {
|
|||
|
||||
// Parse:
|
||||
List<ClassDecl> astRoots = m.parse(fin);
|
||||
|
||||
// Run the semantic check:
|
||||
m.semanticCheck(astRoots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +106,11 @@ public class Main {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public void semanticCheck(List<ClassDecl> astRoots) {
|
||||
{
|
||||
new SemanticAnalyzer(this).check(astRoots);
|
||||
}
|
||||
}
|
||||
|
||||
/** Dumps the AST to the debug stream */
|
||||
private void dumpAst(List<ClassDecl> astRoots) throws IOException {
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
grammar Javali; // parser grammar, parses streams of tokens
|
||||
|
||||
@header {
|
||||
// Java header
|
||||
package cd.frontend.parser;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// PARSER RULES
|
||||
literal
|
||||
: 'null' # NullLiteral
|
||||
| Boolean # BoolLiteral
|
||||
| Integer # IntLiteral
|
||||
;
|
||||
|
||||
// Types
|
||||
type
|
||||
: primitiveType
|
||||
| referenceType
|
||||
;
|
||||
|
||||
referenceType
|
||||
: Ident
|
||||
| arrayType
|
||||
;
|
||||
|
||||
arrayType
|
||||
: Ident '[' ']'
|
||||
| primitiveType '[' ']'
|
||||
;
|
||||
|
||||
primitiveType
|
||||
: 'boolean'
|
||||
| 'int'
|
||||
;
|
||||
|
||||
// Program structure
|
||||
unit
|
||||
: classDecl+ EOF
|
||||
;
|
||||
|
||||
classDecl
|
||||
: 'class' Ident ('extends' Ident)? '{' memberList '}'
|
||||
;
|
||||
|
||||
memberList
|
||||
: (varDecl | methodDecl)*
|
||||
;
|
||||
|
||||
varDecl
|
||||
: type Ident (',' Ident)* ';'
|
||||
;
|
||||
|
||||
methodDecl
|
||||
: (type | 'void') Ident '(' formalParamList? ')' '{' varDecl* stmt* '}'
|
||||
;
|
||||
|
||||
formalParamList
|
||||
: type Ident (',' type Ident)*
|
||||
;
|
||||
|
||||
// Statements
|
||||
stmt
|
||||
: assignmentStmt
|
||||
| methodCallStmt
|
||||
| ifStmt
|
||||
| whileStmt
|
||||
| returnStmt
|
||||
| writeStmt
|
||||
;
|
||||
|
||||
stmtBlock
|
||||
: '{' stmt* '}'
|
||||
;
|
||||
|
||||
methodCallStmt
|
||||
: Ident '(' actualParamList? ')' ';' # LocalMethodCallStmt
|
||||
| identAccess '.' Ident '(' actualParamList? ')' ';' # ObjectMethodCallStmt
|
||||
;
|
||||
|
||||
assignmentStmt
|
||||
: identAccess '=' (expr | newExpr | readExpr) ';'
|
||||
;
|
||||
|
||||
writeStmt
|
||||
: 'write' '(' expr ')' ';' # Write
|
||||
| 'writeln' '(' ')' ';' # WriteLn
|
||||
;
|
||||
|
||||
ifStmt
|
||||
: 'if' '(' expr ')' stmtBlock ('else' stmtBlock)?
|
||||
;
|
||||
|
||||
whileStmt
|
||||
: 'while' '(' expr ')' stmtBlock
|
||||
;
|
||||
|
||||
returnStmt
|
||||
: 'return' expr? ';'
|
||||
;
|
||||
|
||||
// Expressions
|
||||
newExpr
|
||||
: 'new' Ident '(' ')' # NewObject
|
||||
| 'new' Ident '[' expr ']' # NewObjectArray
|
||||
| 'new' primitiveType '[' expr ']' # NewPrimitiveArray
|
||||
;
|
||||
|
||||
readExpr
|
||||
: 'read' '(' ')'
|
||||
;
|
||||
|
||||
actualParamList
|
||||
: expr (',' expr)*
|
||||
;
|
||||
|
||||
identAccess
|
||||
: Ident # AccessLocalField
|
||||
| 'this' # AccessThis
|
||||
| identAccess '.' Ident # AccessObjectField
|
||||
| identAccess '[' expr ']' # AccessArray
|
||||
| Ident '(' actualParamList? ')' # AccessLocalMethod
|
||||
| identAccess '.' Ident '(' actualParamList? ')'# AccessObjectMethod
|
||||
;
|
||||
|
||||
expr
|
||||
: literal # ExprConstant
|
||||
| identAccess # ExprIdentAccess
|
||||
| '(' expr ')' # ExprParentheses
|
||||
| ('+'|'-'|'!') expr # ExprUnary
|
||||
| '(' referenceType ')' expr # ExprCast
|
||||
| expr ('*'|'/'|'%') expr # ExprBinary
|
||||
| expr ('+'|'-') expr # ExprBinary
|
||||
| expr ('<'|'>'|'<='|'>=') expr # ExprBinary
|
||||
| expr ('=='|'!=') expr # ExprBinary
|
||||
| expr '&&' expr # ExprBinary
|
||||
| expr '||' expr # ExprBinary
|
||||
;
|
||||
|
||||
|
||||
// LEXER RULES
|
||||
fragment
|
||||
Letter
|
||||
: 'A'..'Z'
|
||||
| 'a'..'z'
|
||||
;
|
||||
|
||||
fragment
|
||||
Digit
|
||||
: '0'..'9'
|
||||
;
|
||||
|
||||
fragment
|
||||
HexDigit
|
||||
: Digit
|
||||
| 'a'..'f'
|
||||
| 'A'..'F'
|
||||
;
|
||||
|
||||
fragment
|
||||
Decimal
|
||||
: '0'
|
||||
| '1'..'9' Digit*
|
||||
;
|
||||
|
||||
fragment
|
||||
Hexadecimal
|
||||
: ('0x'|'0X') HexDigit+
|
||||
;
|
||||
|
||||
Integer
|
||||
: Decimal
|
||||
| Hexadecimal
|
||||
;
|
||||
|
||||
Boolean
|
||||
: 'false'
|
||||
| 'true'
|
||||
;
|
||||
|
||||
Ident
|
||||
: Letter (Letter|Digit)*
|
||||
;
|
||||
|
||||
|
||||
|
||||
// comments and white space does not produce tokens:
|
||||
COMMENT
|
||||
: '/*' .*? '*/' -> skip
|
||||
;
|
||||
|
||||
LINE_COMMENT
|
||||
: '//' ~('\n'|'\r')* -> skip
|
||||
;
|
||||
|
||||
WS
|
||||
: (' '|'\r'|'\t'|'\n') -> skip
|
||||
;
|
||||
|
||||
|
||||
// handle characters which failed to match any other token
|
||||
ErrorCharacter : . ;
|
File diff suppressed because one or more lines are too long
|
@ -1,85 +0,0 @@
|
|||
T__0=1
|
||||
T__1=2
|
||||
T__2=3
|
||||
T__3=4
|
||||
T__4=5
|
||||
T__5=6
|
||||
T__6=7
|
||||
T__7=8
|
||||
T__8=9
|
||||
T__9=10
|
||||
T__10=11
|
||||
T__11=12
|
||||
T__12=13
|
||||
T__13=14
|
||||
T__14=15
|
||||
T__15=16
|
||||
T__16=17
|
||||
T__17=18
|
||||
T__18=19
|
||||
T__19=20
|
||||
T__20=21
|
||||
T__21=22
|
||||
T__22=23
|
||||
T__23=24
|
||||
T__24=25
|
||||
T__25=26
|
||||
T__26=27
|
||||
T__27=28
|
||||
T__28=29
|
||||
T__29=30
|
||||
T__30=31
|
||||
T__31=32
|
||||
T__32=33
|
||||
T__33=34
|
||||
T__34=35
|
||||
T__35=36
|
||||
T__36=37
|
||||
T__37=38
|
||||
T__38=39
|
||||
Integer=40
|
||||
Boolean=41
|
||||
Ident=42
|
||||
COMMENT=43
|
||||
LINE_COMMENT=44
|
||||
WS=45
|
||||
ErrorCharacter=46
|
||||
'null'=1
|
||||
'['=2
|
||||
']'=3
|
||||
'boolean'=4
|
||||
'int'=5
|
||||
'class'=6
|
||||
'extends'=7
|
||||
'{'=8
|
||||
'}'=9
|
||||
','=10
|
||||
';'=11
|
||||
'void'=12
|
||||
'('=13
|
||||
')'=14
|
||||
'.'=15
|
||||
'='=16
|
||||
'write'=17
|
||||
'writeln'=18
|
||||
'if'=19
|
||||
'else'=20
|
||||
'while'=21
|
||||
'return'=22
|
||||
'new'=23
|
||||
'read'=24
|
||||
'this'=25
|
||||
'+'=26
|
||||
'-'=27
|
||||
'!'=28
|
||||
'*'=29
|
||||
'/'=30
|
||||
'%'=31
|
||||
'<'=32
|
||||
'>'=33
|
||||
'<='=34
|
||||
'>='=35
|
||||
'=='=36
|
||||
'!='=37
|
||||
'&&'=38
|
||||
'||'=39
|
|
@ -1,329 +0,0 @@
|
|||
package cd.frontend.parser;
|
||||
|
||||
import cd.frontend.parser.JavaliParser.*;
|
||||
import cd.ir.Ast;
|
||||
import cd.ir.Ast.*;
|
||||
import cd.ir.Ast.BinaryOp.BOp;
|
||||
import cd.ir.Ast.UnaryOp.UOp;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class JavaliAstVisitor extends JavaliBaseVisitor<Ast> {
|
||||
|
||||
public List<ClassDecl> classDecls = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Ast visitUnit(UnitContext ctx) {
|
||||
for (ClassDeclContext classDeclContext : ctx.classDecl())
|
||||
classDecls.add((ClassDecl) visit(classDeclContext));
|
||||
return new Seq(new ArrayList<>(classDecls));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitClassDecl(ClassDeclContext ctx) {
|
||||
String name = ctx.Ident(0).getText();
|
||||
String superClass = "Object"; // Common superclass
|
||||
if (ctx.Ident().size() == 2)
|
||||
superClass = ctx.Ident(1).getText();
|
||||
Seq members = (Seq) visit(ctx.memberList());
|
||||
return new ClassDecl(name, superClass, members.children());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitMemberList(MemberListContext ctx) {
|
||||
if (ctx.children == null) {
|
||||
return new Seq(new ArrayList<>());
|
||||
}
|
||||
List<Ast> list = new ArrayList<>(ctx.children.size());
|
||||
for (ParseTree parseTree : ctx.children) {
|
||||
if (parseTree instanceof VarDeclContext) {
|
||||
Seq seqVars = (Seq) visit(parseTree);
|
||||
list.addAll(seqVars.children());
|
||||
} else {
|
||||
assert parseTree instanceof MethodDeclContext;
|
||||
list.add(visit(parseTree));
|
||||
}
|
||||
}
|
||||
return new Seq(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitVarDecl(VarDeclContext ctx) {
|
||||
List<Ast> list = new ArrayList<>(ctx.Ident().size());
|
||||
String type = ctx.type().getText();
|
||||
for (TerminalNode n : ctx.Ident())
|
||||
list.add(new VarDecl(type, n.getText()));
|
||||
return new Seq(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitMethodDecl(MethodDeclContext ctx) {
|
||||
List<String> argumentTypes = new ArrayList<>();
|
||||
List<String> argumentNames = new ArrayList<>();
|
||||
if (ctx.formalParamList() != null) {
|
||||
Seq paramList = (Seq) visit(ctx.formalParamList());
|
||||
for (Ast ast : paramList.children()) {
|
||||
VarDecl var = (VarDecl) ast;
|
||||
argumentNames.add(var.name);
|
||||
argumentTypes.add(var.type);
|
||||
}
|
||||
}
|
||||
|
||||
List<Ast> decls = new ArrayList<>(ctx.varDecl().size());
|
||||
for (VarDeclContext varDecl : ctx.varDecl()) {
|
||||
Seq declarationSeq = (Seq) visit(varDecl);
|
||||
decls.addAll(declarationSeq.children());
|
||||
}
|
||||
|
||||
List<Ast> stmts = new ArrayList<>(ctx.stmt().size());
|
||||
for (StmtContext s : ctx.stmt())
|
||||
stmts.add(visit(s));
|
||||
|
||||
return new MethodDecl(
|
||||
ctx.type() == null ? "void" : ctx.type().getText(),
|
||||
ctx.Ident().getText(),
|
||||
argumentTypes,
|
||||
argumentNames,
|
||||
new Seq(decls),
|
||||
new Seq(stmts)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitFormalParamList(FormalParamListContext ctx) {
|
||||
List<Ast> list = new ArrayList<>(ctx.type().size());
|
||||
for (int i = 0; i < ctx.type().size(); i++) {
|
||||
String type = ctx.type(i).getText();
|
||||
String name = ctx.Ident(i).getText();
|
||||
list.add(new VarDecl(type, name));
|
||||
}
|
||||
return new Seq(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitStmt(StmtContext ctx) {
|
||||
return visit(ctx.children.get(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitStmtBlock(StmtBlockContext ctx) {
|
||||
List<Ast> list = new ArrayList<>(ctx.stmt().size());
|
||||
for (StmtContext stmtContext : ctx.stmt())
|
||||
list.add(visit(stmtContext));
|
||||
return new Seq(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitLocalMethodCallStmt(LocalMethodCallStmtContext ctx) {
|
||||
return new MethodCall(new MethodCallExpr(
|
||||
new ThisRef(),
|
||||
ctx.Ident().getText(),
|
||||
getParams(ctx.actualParamList())
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitObjectMethodCallStmt(ObjectMethodCallStmtContext ctx) {
|
||||
return new MethodCall(new MethodCallExpr(
|
||||
(Expr) visit(ctx.identAccess()),
|
||||
ctx.Ident().getText(),
|
||||
getParams(ctx.actualParamList())
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAssignmentStmt(AssignmentStmtContext ctx) {
|
||||
Expr left = (Expr) visit(ctx.children.get(0));
|
||||
Expr right = (Expr) visit(ctx.children.get(2));
|
||||
return new Assign(left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitWrite(WriteContext ctx) {
|
||||
return new BuiltInWrite((Expr) visit(ctx.expr()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitWriteLn(WriteLnContext ctx) {
|
||||
return new BuiltInWriteln();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitIfStmt(IfStmtContext ctx) {
|
||||
Expr condition = (Expr) visit(ctx.expr());
|
||||
Ast then = visit(ctx.stmtBlock(0));
|
||||
Ast otherwise = new Nop();
|
||||
if (ctx.stmtBlock().size() == 2)
|
||||
otherwise = visit(ctx.stmtBlock(1));
|
||||
return new IfElse(condition, then, otherwise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitWhileStmt(WhileStmtContext ctx) {
|
||||
Expr condition = (Expr) visit(ctx.expr());
|
||||
Ast body = visit(ctx.stmtBlock());
|
||||
return new WhileLoop(condition, body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitReturnStmt(ReturnStmtContext ctx) {
|
||||
if (ctx.expr() != null)
|
||||
return new ReturnStmt((Expr) visit(ctx.expr()));
|
||||
else
|
||||
return new ReturnStmt(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitNewObject(NewObjectContext ctx) {
|
||||
return new NewObject(ctx.Ident().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitNewObjectArray(NewObjectArrayContext ctx) {
|
||||
String type = ctx.Ident().getText();
|
||||
Expr size = (Expr) visit(ctx.expr());
|
||||
return new NewArray(type + "[]", size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitNewPrimitiveArray(NewPrimitiveArrayContext ctx) {
|
||||
String type = ctx.primitiveType().getText();
|
||||
Expr size = (Expr) visit(ctx.expr());
|
||||
return new NewArray(type + "[]", size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitReadExpr(ReadExprContext ctx) {
|
||||
return new BuiltInRead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitActualParamList(ActualParamListContext ctx) {
|
||||
List<Ast> list = new ArrayList<>(ctx.expr().size());
|
||||
for (ExprContext exprContext : ctx.expr())
|
||||
list.add(visit(exprContext));
|
||||
return new Seq(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAccessThis(AccessThisContext ctx) {
|
||||
return new ThisRef();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAccessLocalField(AccessLocalFieldContext ctx) {
|
||||
return new Var(ctx.Ident().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAccessObjectField(AccessObjectFieldContext ctx) {
|
||||
Expr arg = (Expr) visit(ctx.identAccess());
|
||||
String fieldName = ctx.Ident().getText();
|
||||
return new Field(arg, fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAccessLocalMethod(AccessLocalMethodContext ctx) {
|
||||
return new MethodCallExpr(
|
||||
new ThisRef(),
|
||||
ctx.Ident().getText(),
|
||||
getParams(ctx.actualParamList())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAccessArray(AccessArrayContext ctx) {
|
||||
Expr array = (Expr) visit(ctx.identAccess());
|
||||
Expr index = (Expr) visit(ctx.expr());
|
||||
return new Index(array, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitAccessObjectMethod(AccessObjectMethodContext ctx) {
|
||||
return new MethodCallExpr(
|
||||
(Expr) visit(ctx.identAccess()),
|
||||
ctx.Ident().getText(),
|
||||
getParams(ctx.actualParamList())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitExprBinary(ExprBinaryContext ctx) {
|
||||
Expr left = (Expr) visit(ctx.expr(0));
|
||||
Expr right = (Expr) visit(ctx.expr(1));
|
||||
String op = ctx.getChild(1).getText();
|
||||
for (BOp bop : BOp.values())
|
||||
if (bop.repr.equals(op))
|
||||
return new BinaryOp(left, bop, right);
|
||||
throw new RuntimeException("BOp enum is inconsistent with grammar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitExprCast(ExprCastContext ctx) {
|
||||
Expr arg = (Expr) visit(ctx.expr());
|
||||
String typeName = ctx.referenceType().getText();
|
||||
return new Cast(arg, typeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitExprParentheses(ExprParenthesesContext ctx) {
|
||||
return visit(ctx.expr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitExprUnary(ExprUnaryContext ctx) {
|
||||
Expr expr = (Expr) visit(ctx.expr());
|
||||
String op = ctx.getChild(0).getText();
|
||||
for (UOp uop : UOp.values())
|
||||
if (uop.repr.equals(op))
|
||||
return new UnaryOp(uop, expr);
|
||||
throw new RuntimeException("UOp enum is inconsistent with grammar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitExprConstant(ExprConstantContext ctx) {
|
||||
return visit(ctx.literal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitNullLiteral(NullLiteralContext ctx) {
|
||||
return new NullConst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitBoolLiteral(BoolLiteralContext ctx) {
|
||||
return new BooleanConst(ctx.Boolean().getText().equals("true"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitIntLiteral(IntLiteralContext ctx) {
|
||||
try {
|
||||
return new IntConst(Integer.decode(ctx.Integer().getText()));
|
||||
} catch (NumberFormatException exception) {
|
||||
throw new ParseFailure(ctx.start.getLine(), "Value not in 32bit signed int range");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ast visitExprIdentAccess(ExprIdentAccessContext ctx) {
|
||||
return visit(ctx.identAccess());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the parameters for a method call
|
||||
* @param paramListContext Formal parameter list from the ANTRL tree
|
||||
* @return List of parameters for the method call
|
||||
*/
|
||||
private List<Expr> getParams(ActualParamListContext paramListContext) {
|
||||
List<Expr> paramList = new ArrayList<>();
|
||||
if (paramListContext != null) {
|
||||
Seq paramSeq = (Seq) visit(paramListContext);
|
||||
for (Ast ast : paramSeq.children())
|
||||
paramList.add((Expr) ast);
|
||||
}
|
||||
return paramList;
|
||||
}
|
||||
}
|
|
@ -1,297 +0,0 @@
|
|||
// Generated from /home/carlos/eth/cd/nop90/HW2/src/cd/frontend/parser/Javali.g4 by ANTLR 4.7.1
|
||||
|
||||
// Java header
|
||||
package cd.frontend.parser;
|
||||
|
||||
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
|
||||
|
||||
/**
|
||||
* This class provides an empty implementation of {@link JavaliVisitor},
|
||||
* which can be extended to create a visitor which only needs to handle a subset
|
||||
* of the available methods.
|
||||
*
|
||||
* @param <T> The return type of the visit operation. Use {@link Void} for
|
||||
* operations with no return type.
|
||||
*/
|
||||
public class JavaliBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements JavaliVisitor<T> {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNullLiteral(JavaliParser.NullLiteralContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitBoolLiteral(JavaliParser.BoolLiteralContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitIntLiteral(JavaliParser.IntLiteralContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitType(JavaliParser.TypeContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitReferenceType(JavaliParser.ReferenceTypeContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitArrayType(JavaliParser.ArrayTypeContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitPrimitiveType(JavaliParser.PrimitiveTypeContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitUnit(JavaliParser.UnitContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitClassDecl(JavaliParser.ClassDeclContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitMemberList(JavaliParser.MemberListContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitVarDecl(JavaliParser.VarDeclContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitMethodDecl(JavaliParser.MethodDeclContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitFormalParamList(JavaliParser.FormalParamListContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmt(JavaliParser.StmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitStmtBlock(JavaliParser.StmtBlockContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitLocalMethodCallStmt(JavaliParser.LocalMethodCallStmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitObjectMethodCallStmt(JavaliParser.ObjectMethodCallStmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAssignmentStmt(JavaliParser.AssignmentStmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitWrite(JavaliParser.WriteContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitWriteLn(JavaliParser.WriteLnContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitIfStmt(JavaliParser.IfStmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitWhileStmt(JavaliParser.WhileStmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitReturnStmt(JavaliParser.ReturnStmtContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNewObject(JavaliParser.NewObjectContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNewObjectArray(JavaliParser.NewObjectArrayContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNewPrimitiveArray(JavaliParser.NewPrimitiveArrayContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitReadExpr(JavaliParser.ReadExprContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitActualParamList(JavaliParser.ActualParamListContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAccessThis(JavaliParser.AccessThisContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAccessLocalField(JavaliParser.AccessLocalFieldContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAccessObjectField(JavaliParser.AccessObjectFieldContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAccessLocalMethod(JavaliParser.AccessLocalMethodContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAccessArray(JavaliParser.AccessArrayContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitAccessObjectMethod(JavaliParser.AccessObjectMethodContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitExprBinary(JavaliParser.ExprBinaryContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitExprCast(JavaliParser.ExprCastContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitExprParentheses(JavaliParser.ExprParenthesesContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitExprUnary(JavaliParser.ExprUnaryContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitExprConstant(JavaliParser.ExprConstantContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitExprIdentAccess(JavaliParser.ExprIdentAccessContext ctx) { return visitChildren(ctx); }
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,232 +0,0 @@
|
|||
// Generated from /home/carlos/eth/cd/nop90/HW2/src/cd/frontend/parser/Javali.g4 by ANTLR 4.7.1
|
||||
|
||||
// Java header
|
||||
package cd.frontend.parser;
|
||||
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.misc.*;
|
||||
|
||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||
public class JavaliLexer extends Lexer {
|
||||
static { RuntimeMetaData.checkVersion("4.7.1", RuntimeMetaData.VERSION); }
|
||||
|
||||
protected static final DFA[] _decisionToDFA;
|
||||
protected static final PredictionContextCache _sharedContextCache =
|
||||
new PredictionContextCache();
|
||||
public static final int
|
||||
T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9,
|
||||
T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17,
|
||||
T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, T__23=24,
|
||||
T__24=25, T__25=26, T__26=27, T__27=28, T__28=29, T__29=30, T__30=31,
|
||||
T__31=32, T__32=33, T__33=34, T__34=35, T__35=36, T__36=37, T__37=38,
|
||||
T__38=39, Integer=40, Boolean=41, Ident=42, COMMENT=43, LINE_COMMENT=44,
|
||||
WS=45, ErrorCharacter=46;
|
||||
public static String[] channelNames = {
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
|
||||
};
|
||||
|
||||
public static String[] modeNames = {
|
||||
"DEFAULT_MODE"
|
||||
};
|
||||
|
||||
public static final String[] ruleNames = {
|
||||
"T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8",
|
||||
"T__9", "T__10", "T__11", "T__12", "T__13", "T__14", "T__15", "T__16",
|
||||
"T__17", "T__18", "T__19", "T__20", "T__21", "T__22", "T__23", "T__24",
|
||||
"T__25", "T__26", "T__27", "T__28", "T__29", "T__30", "T__31", "T__32",
|
||||
"T__33", "T__34", "T__35", "T__36", "T__37", "T__38", "Letter", "Digit",
|
||||
"HexDigit", "Decimal", "Hexadecimal", "Integer", "Boolean", "Ident", "COMMENT",
|
||||
"LINE_COMMENT", "WS", "ErrorCharacter"
|
||||
};
|
||||
|
||||
private static final String[] _LITERAL_NAMES = {
|
||||
null, "'null'", "'['", "']'", "'boolean'", "'int'", "'class'", "'extends'",
|
||||
"'{'", "'}'", "','", "';'", "'void'", "'('", "')'", "'.'", "'='", "'write'",
|
||||
"'writeln'", "'if'", "'else'", "'while'", "'return'", "'new'", "'read'",
|
||||
"'this'", "'+'", "'-'", "'!'", "'*'", "'/'", "'%'", "'<'", "'>'", "'<='",
|
||||
"'>='", "'=='", "'!='", "'&&'", "'||'"
|
||||
};
|
||||
private static final String[] _SYMBOLIC_NAMES = {
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, "Integer", "Boolean", "Ident", "COMMENT", "LINE_COMMENT",
|
||||
"WS", "ErrorCharacter"
|
||||
};
|
||||
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #VOCABULARY} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String[] tokenNames;
|
||||
static {
|
||||
tokenNames = new String[_SYMBOLIC_NAMES.length];
|
||||
for (int i = 0; i < tokenNames.length; i++) {
|
||||
tokenNames[i] = VOCABULARY.getLiteralName(i);
|
||||
if (tokenNames[i] == null) {
|
||||
tokenNames[i] = VOCABULARY.getSymbolicName(i);
|
||||
}
|
||||
|
||||
if (tokenNames[i] == null) {
|
||||
tokenNames[i] = "<INVALID>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String[] getTokenNames() {
|
||||
return tokenNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Vocabulary getVocabulary() {
|
||||
return VOCABULARY;
|
||||
}
|
||||
|
||||
|
||||
public JavaliLexer(CharStream input) {
|
||||
super(input);
|
||||
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGrammarFileName() { return "Javali.g4"; }
|
||||
|
||||
@Override
|
||||
public String[] getRuleNames() { return ruleNames; }
|
||||
|
||||
@Override
|
||||
public String getSerializedATN() { return _serializedATN; }
|
||||
|
||||
@Override
|
||||
public String[] getChannelNames() { return channelNames; }
|
||||
|
||||
@Override
|
||||
public String[] getModeNames() { return modeNames; }
|
||||
|
||||
@Override
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
public static final String _serializedATN =
|
||||
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\60\u0147\b\1\4\2"+
|
||||
"\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+
|
||||
"\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+
|
||||
"\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+
|
||||
"\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t"+
|
||||
" \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t"+
|
||||
"+\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64"+
|
||||
"\t\64\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5"+
|
||||
"\3\5\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3"+
|
||||
"\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\16\3\16"+
|
||||
"\3\17\3\17\3\20\3\20\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23"+
|
||||
"\3\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25"+
|
||||
"\3\26\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\30"+
|
||||
"\3\30\3\30\3\30\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\33"+
|
||||
"\3\33\3\34\3\34\3\35\3\35\3\36\3\36\3\37\3\37\3 \3 \3!\3!\3\"\3\"\3#\3"+
|
||||
"#\3#\3$\3$\3$\3%\3%\3%\3&\3&\3&\3\'\3\'\3\'\3(\3(\3(\3)\3)\3*\3*\3+\3"+
|
||||
"+\5+\u00fb\n+\3,\3,\3,\7,\u0100\n,\f,\16,\u0103\13,\5,\u0105\n,\3-\3-"+
|
||||
"\3-\3-\5-\u010b\n-\3-\6-\u010e\n-\r-\16-\u010f\3.\3.\5.\u0114\n.\3/\3"+
|
||||
"/\3/\3/\3/\3/\3/\3/\3/\5/\u011f\n/\3\60\3\60\3\60\7\60\u0124\n\60\f\60"+
|
||||
"\16\60\u0127\13\60\3\61\3\61\3\61\3\61\7\61\u012d\n\61\f\61\16\61\u0130"+
|
||||
"\13\61\3\61\3\61\3\61\3\61\3\61\3\62\3\62\3\62\3\62\7\62\u013b\n\62\f"+
|
||||
"\62\16\62\u013e\13\62\3\62\3\62\3\63\3\63\3\63\3\63\3\64\3\64\3\u012e"+
|
||||
"\2\65\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35"+
|
||||
"\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67\359\36"+
|
||||
";\37= ?!A\"C#E$G%I&K\'M(O)Q\2S\2U\2W\2Y\2[*]+_,a-c.e/g\60\3\2\6\4\2C\\"+
|
||||
"c|\4\2CHch\4\2\f\f\17\17\5\2\13\f\17\17\"\"\2\u014c\2\3\3\2\2\2\2\5\3"+
|
||||
"\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2"+
|
||||
"\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3"+
|
||||
"\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'"+
|
||||
"\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63"+
|
||||
"\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2"+
|
||||
"?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3"+
|
||||
"\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2"+
|
||||
"\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\3i\3\2\2\2\5n\3\2\2\2\7p\3\2\2\2\t"+
|
||||
"r\3\2\2\2\13z\3\2\2\2\r~\3\2\2\2\17\u0084\3\2\2\2\21\u008c\3\2\2\2\23"+
|
||||
"\u008e\3\2\2\2\25\u0090\3\2\2\2\27\u0092\3\2\2\2\31\u0094\3\2\2\2\33\u0099"+
|
||||
"\3\2\2\2\35\u009b\3\2\2\2\37\u009d\3\2\2\2!\u009f\3\2\2\2#\u00a1\3\2\2"+
|
||||
"\2%\u00a7\3\2\2\2\'\u00af\3\2\2\2)\u00b2\3\2\2\2+\u00b7\3\2\2\2-\u00bd"+
|
||||
"\3\2\2\2/\u00c4\3\2\2\2\61\u00c8\3\2\2\2\63\u00cd\3\2\2\2\65\u00d2\3\2"+
|
||||
"\2\2\67\u00d4\3\2\2\29\u00d6\3\2\2\2;\u00d8\3\2\2\2=\u00da\3\2\2\2?\u00dc"+
|
||||
"\3\2\2\2A\u00de\3\2\2\2C\u00e0\3\2\2\2E\u00e2\3\2\2\2G\u00e5\3\2\2\2I"+
|
||||
"\u00e8\3\2\2\2K\u00eb\3\2\2\2M\u00ee\3\2\2\2O\u00f1\3\2\2\2Q\u00f4\3\2"+
|
||||
"\2\2S\u00f6\3\2\2\2U\u00fa\3\2\2\2W\u0104\3\2\2\2Y\u010a\3\2\2\2[\u0113"+
|
||||
"\3\2\2\2]\u011e\3\2\2\2_\u0120\3\2\2\2a\u0128\3\2\2\2c\u0136\3\2\2\2e"+
|
||||
"\u0141\3\2\2\2g\u0145\3\2\2\2ij\7p\2\2jk\7w\2\2kl\7n\2\2lm\7n\2\2m\4\3"+
|
||||
"\2\2\2no\7]\2\2o\6\3\2\2\2pq\7_\2\2q\b\3\2\2\2rs\7d\2\2st\7q\2\2tu\7q"+
|
||||
"\2\2uv\7n\2\2vw\7g\2\2wx\7c\2\2xy\7p\2\2y\n\3\2\2\2z{\7k\2\2{|\7p\2\2"+
|
||||
"|}\7v\2\2}\f\3\2\2\2~\177\7e\2\2\177\u0080\7n\2\2\u0080\u0081\7c\2\2\u0081"+
|
||||
"\u0082\7u\2\2\u0082\u0083\7u\2\2\u0083\16\3\2\2\2\u0084\u0085\7g\2\2\u0085"+
|
||||
"\u0086\7z\2\2\u0086\u0087\7v\2\2\u0087\u0088\7g\2\2\u0088\u0089\7p\2\2"+
|
||||
"\u0089\u008a\7f\2\2\u008a\u008b\7u\2\2\u008b\20\3\2\2\2\u008c\u008d\7"+
|
||||
"}\2\2\u008d\22\3\2\2\2\u008e\u008f\7\177\2\2\u008f\24\3\2\2\2\u0090\u0091"+
|
||||
"\7.\2\2\u0091\26\3\2\2\2\u0092\u0093\7=\2\2\u0093\30\3\2\2\2\u0094\u0095"+
|
||||
"\7x\2\2\u0095\u0096\7q\2\2\u0096\u0097\7k\2\2\u0097\u0098\7f\2\2\u0098"+
|
||||
"\32\3\2\2\2\u0099\u009a\7*\2\2\u009a\34\3\2\2\2\u009b\u009c\7+\2\2\u009c"+
|
||||
"\36\3\2\2\2\u009d\u009e\7\60\2\2\u009e \3\2\2\2\u009f\u00a0\7?\2\2\u00a0"+
|
||||
"\"\3\2\2\2\u00a1\u00a2\7y\2\2\u00a2\u00a3\7t\2\2\u00a3\u00a4\7k\2\2\u00a4"+
|
||||
"\u00a5\7v\2\2\u00a5\u00a6\7g\2\2\u00a6$\3\2\2\2\u00a7\u00a8\7y\2\2\u00a8"+
|
||||
"\u00a9\7t\2\2\u00a9\u00aa\7k\2\2\u00aa\u00ab\7v\2\2\u00ab\u00ac\7g\2\2"+
|
||||
"\u00ac\u00ad\7n\2\2\u00ad\u00ae\7p\2\2\u00ae&\3\2\2\2\u00af\u00b0\7k\2"+
|
||||
"\2\u00b0\u00b1\7h\2\2\u00b1(\3\2\2\2\u00b2\u00b3\7g\2\2\u00b3\u00b4\7"+
|
||||
"n\2\2\u00b4\u00b5\7u\2\2\u00b5\u00b6\7g\2\2\u00b6*\3\2\2\2\u00b7\u00b8"+
|
||||
"\7y\2\2\u00b8\u00b9\7j\2\2\u00b9\u00ba\7k\2\2\u00ba\u00bb\7n\2\2\u00bb"+
|
||||
"\u00bc\7g\2\2\u00bc,\3\2\2\2\u00bd\u00be\7t\2\2\u00be\u00bf\7g\2\2\u00bf"+
|
||||
"\u00c0\7v\2\2\u00c0\u00c1\7w\2\2\u00c1\u00c2\7t\2\2\u00c2\u00c3\7p\2\2"+
|
||||
"\u00c3.\3\2\2\2\u00c4\u00c5\7p\2\2\u00c5\u00c6\7g\2\2\u00c6\u00c7\7y\2"+
|
||||
"\2\u00c7\60\3\2\2\2\u00c8\u00c9\7t\2\2\u00c9\u00ca\7g\2\2\u00ca\u00cb"+
|
||||
"\7c\2\2\u00cb\u00cc\7f\2\2\u00cc\62\3\2\2\2\u00cd\u00ce\7v\2\2\u00ce\u00cf"+
|
||||
"\7j\2\2\u00cf\u00d0\7k\2\2\u00d0\u00d1\7u\2\2\u00d1\64\3\2\2\2\u00d2\u00d3"+
|
||||
"\7-\2\2\u00d3\66\3\2\2\2\u00d4\u00d5\7/\2\2\u00d58\3\2\2\2\u00d6\u00d7"+
|
||||
"\7#\2\2\u00d7:\3\2\2\2\u00d8\u00d9\7,\2\2\u00d9<\3\2\2\2\u00da\u00db\7"+
|
||||
"\61\2\2\u00db>\3\2\2\2\u00dc\u00dd\7\'\2\2\u00dd@\3\2\2\2\u00de\u00df"+
|
||||
"\7>\2\2\u00dfB\3\2\2\2\u00e0\u00e1\7@\2\2\u00e1D\3\2\2\2\u00e2\u00e3\7"+
|
||||
">\2\2\u00e3\u00e4\7?\2\2\u00e4F\3\2\2\2\u00e5\u00e6\7@\2\2\u00e6\u00e7"+
|
||||
"\7?\2\2\u00e7H\3\2\2\2\u00e8\u00e9\7?\2\2\u00e9\u00ea\7?\2\2\u00eaJ\3"+
|
||||
"\2\2\2\u00eb\u00ec\7#\2\2\u00ec\u00ed\7?\2\2\u00edL\3\2\2\2\u00ee\u00ef"+
|
||||
"\7(\2\2\u00ef\u00f0\7(\2\2\u00f0N\3\2\2\2\u00f1\u00f2\7~\2\2\u00f2\u00f3"+
|
||||
"\7~\2\2\u00f3P\3\2\2\2\u00f4\u00f5\t\2\2\2\u00f5R\3\2\2\2\u00f6\u00f7"+
|
||||
"\4\62;\2\u00f7T\3\2\2\2\u00f8\u00fb\5S*\2\u00f9\u00fb\t\3\2\2\u00fa\u00f8"+
|
||||
"\3\2\2\2\u00fa\u00f9\3\2\2\2\u00fbV\3\2\2\2\u00fc\u0105\7\62\2\2\u00fd"+
|
||||
"\u0101\4\63;\2\u00fe\u0100\5S*\2\u00ff\u00fe\3\2\2\2\u0100\u0103\3\2\2"+
|
||||
"\2\u0101\u00ff\3\2\2\2\u0101\u0102\3\2\2\2\u0102\u0105\3\2\2\2\u0103\u0101"+
|
||||
"\3\2\2\2\u0104\u00fc\3\2\2\2\u0104\u00fd\3\2\2\2\u0105X\3\2\2\2\u0106"+
|
||||
"\u0107\7\62\2\2\u0107\u010b\7z\2\2\u0108\u0109\7\62\2\2\u0109\u010b\7"+
|
||||
"Z\2\2\u010a\u0106\3\2\2\2\u010a\u0108\3\2\2\2\u010b\u010d\3\2\2\2\u010c"+
|
||||
"\u010e\5U+\2\u010d\u010c\3\2\2\2\u010e\u010f\3\2\2\2\u010f\u010d\3\2\2"+
|
||||
"\2\u010f\u0110\3\2\2\2\u0110Z\3\2\2\2\u0111\u0114\5W,\2\u0112\u0114\5"+
|
||||
"Y-\2\u0113\u0111\3\2\2\2\u0113\u0112\3\2\2\2\u0114\\\3\2\2\2\u0115\u0116"+
|
||||
"\7h\2\2\u0116\u0117\7c\2\2\u0117\u0118\7n\2\2\u0118\u0119\7u\2\2\u0119"+
|
||||
"\u011f\7g\2\2\u011a\u011b\7v\2\2\u011b\u011c\7t\2\2\u011c\u011d\7w\2\2"+
|
||||
"\u011d\u011f\7g\2\2\u011e\u0115\3\2\2\2\u011e\u011a\3\2\2\2\u011f^\3\2"+
|
||||
"\2\2\u0120\u0125\5Q)\2\u0121\u0124\5Q)\2\u0122\u0124\5S*\2\u0123\u0121"+
|
||||
"\3\2\2\2\u0123\u0122\3\2\2\2\u0124\u0127\3\2\2\2\u0125\u0123\3\2\2\2\u0125"+
|
||||
"\u0126\3\2\2\2\u0126`\3\2\2\2\u0127\u0125\3\2\2\2\u0128\u0129\7\61\2\2"+
|
||||
"\u0129\u012a\7,\2\2\u012a\u012e\3\2\2\2\u012b\u012d\13\2\2\2\u012c\u012b"+
|
||||
"\3\2\2\2\u012d\u0130\3\2\2\2\u012e\u012f\3\2\2\2\u012e\u012c\3\2\2\2\u012f"+
|
||||
"\u0131\3\2\2\2\u0130\u012e\3\2\2\2\u0131\u0132\7,\2\2\u0132\u0133\7\61"+
|
||||
"\2\2\u0133\u0134\3\2\2\2\u0134\u0135\b\61\2\2\u0135b\3\2\2\2\u0136\u0137"+
|
||||
"\7\61\2\2\u0137\u0138\7\61\2\2\u0138\u013c\3\2\2\2\u0139\u013b\n\4\2\2"+
|
||||
"\u013a\u0139\3\2\2\2\u013b\u013e\3\2\2\2\u013c\u013a\3\2\2\2\u013c\u013d"+
|
||||
"\3\2\2\2\u013d\u013f\3\2\2\2\u013e\u013c\3\2\2\2\u013f\u0140\b\62\2\2"+
|
||||
"\u0140d\3\2\2\2\u0141\u0142\t\5\2\2\u0142\u0143\3\2\2\2\u0143\u0144\b"+
|
||||
"\63\2\2\u0144f\3\2\2\2\u0145\u0146\13\2\2\2\u0146h\3\2\2\2\16\2\u00fa"+
|
||||
"\u0101\u0104\u010a\u010f\u0113\u011e\u0123\u0125\u012e\u013c\3\b\2\2";
|
||||
public static final ATN _ATN =
|
||||
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
||||
static {
|
||||
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
|
||||
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
|
||||
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
T__0=1
|
||||
T__1=2
|
||||
T__2=3
|
||||
T__3=4
|
||||
T__4=5
|
||||
T__5=6
|
||||
T__6=7
|
||||
T__7=8
|
||||
T__8=9
|
||||
T__9=10
|
||||
T__10=11
|
||||
T__11=12
|
||||
T__12=13
|
||||
T__13=14
|
||||
T__14=15
|
||||
T__15=16
|
||||
T__16=17
|
||||
T__17=18
|
||||
T__18=19
|
||||
T__19=20
|
||||
T__20=21
|
||||
T__21=22
|
||||
T__22=23
|
||||
T__23=24
|
||||
T__24=25
|
||||
T__25=26
|
||||
T__26=27
|
||||
T__27=28
|
||||
T__28=29
|
||||
T__29=30
|
||||
T__30=31
|
||||
T__31=32
|
||||
T__32=33
|
||||
T__33=34
|
||||
T__34=35
|
||||
T__35=36
|
||||
T__36=37
|
||||
T__37=38
|
||||
T__38=39
|
||||
Integer=40
|
||||
Boolean=41
|
||||
Ident=42
|
||||
COMMENT=43
|
||||
LINE_COMMENT=44
|
||||
WS=45
|
||||
ErrorCharacter=46
|
||||
'null'=1
|
||||
'['=2
|
||||
']'=3
|
||||
'boolean'=4
|
||||
'int'=5
|
||||
'class'=6
|
||||
'extends'=7
|
||||
'{'=8
|
||||
'}'=9
|
||||
','=10
|
||||
';'=11
|
||||
'void'=12
|
||||
'('=13
|
||||
')'=14
|
||||
'.'=15
|
||||
'='=16
|
||||
'write'=17
|
||||
'writeln'=18
|
||||
'if'=19
|
||||
'else'=20
|
||||
'while'=21
|
||||
'return'=22
|
||||
'new'=23
|
||||
'read'=24
|
||||
'this'=25
|
||||
'+'=26
|
||||
'-'=27
|
||||
'!'=28
|
||||
'*'=29
|
||||
'/'=30
|
||||
'%'=31
|
||||
'<'=32
|
||||
'>'=33
|
||||
'<='=34
|
||||
'>='=35
|
||||
'=='=36
|
||||
'!='=37
|
||||
'&&'=38
|
||||
'||'=39
|
File diff suppressed because it is too large
Load diff
|
@ -1,278 +0,0 @@
|
|||
// Generated from /home/carlos/eth/cd/nop90/HW2/src/cd/frontend/parser/Javali.g4 by ANTLR 4.7.1
|
||||
|
||||
// Java header
|
||||
package cd.frontend.parser;
|
||||
|
||||
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
|
||||
|
||||
/**
|
||||
* This interface defines a complete generic visitor for a parse tree produced
|
||||
* by {@link JavaliParser}.
|
||||
*
|
||||
* @param <T> The return type of the visit operation. Use {@link Void} for
|
||||
* operations with no return type.
|
||||
*/
|
||||
public interface JavaliVisitor<T> extends ParseTreeVisitor<T> {
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code NullLiteral}
|
||||
* labeled alternative in {@link JavaliParser#literal}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitNullLiteral(JavaliParser.NullLiteralContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code BoolLiteral}
|
||||
* labeled alternative in {@link JavaliParser#literal}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitBoolLiteral(JavaliParser.BoolLiteralContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code IntLiteral}
|
||||
* labeled alternative in {@link JavaliParser#literal}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitIntLiteral(JavaliParser.IntLiteralContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#type}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitType(JavaliParser.TypeContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#referenceType}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitReferenceType(JavaliParser.ReferenceTypeContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#arrayType}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitArrayType(JavaliParser.ArrayTypeContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#primitiveType}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitPrimitiveType(JavaliParser.PrimitiveTypeContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#unit}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitUnit(JavaliParser.UnitContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#classDecl}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitClassDecl(JavaliParser.ClassDeclContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#memberList}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitMemberList(JavaliParser.MemberListContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#varDecl}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitVarDecl(JavaliParser.VarDeclContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#methodDecl}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitMethodDecl(JavaliParser.MethodDeclContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#formalParamList}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitFormalParamList(JavaliParser.FormalParamListContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#stmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmt(JavaliParser.StmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#stmtBlock}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitStmtBlock(JavaliParser.StmtBlockContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code LocalMethodCallStmt}
|
||||
* labeled alternative in {@link JavaliParser#methodCallStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitLocalMethodCallStmt(JavaliParser.LocalMethodCallStmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ObjectMethodCallStmt}
|
||||
* labeled alternative in {@link JavaliParser#methodCallStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitObjectMethodCallStmt(JavaliParser.ObjectMethodCallStmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#assignmentStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAssignmentStmt(JavaliParser.AssignmentStmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code Write}
|
||||
* labeled alternative in {@link JavaliParser#writeStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitWrite(JavaliParser.WriteContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code WriteLn}
|
||||
* labeled alternative in {@link JavaliParser#writeStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitWriteLn(JavaliParser.WriteLnContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#ifStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitIfStmt(JavaliParser.IfStmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#whileStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitWhileStmt(JavaliParser.WhileStmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#returnStmt}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitReturnStmt(JavaliParser.ReturnStmtContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code NewObject}
|
||||
* labeled alternative in {@link JavaliParser#newExpr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitNewObject(JavaliParser.NewObjectContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code NewObjectArray}
|
||||
* labeled alternative in {@link JavaliParser#newExpr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitNewObjectArray(JavaliParser.NewObjectArrayContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code NewPrimitiveArray}
|
||||
* labeled alternative in {@link JavaliParser#newExpr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitNewPrimitiveArray(JavaliParser.NewPrimitiveArrayContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#readExpr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitReadExpr(JavaliParser.ReadExprContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link JavaliParser#actualParamList}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitActualParamList(JavaliParser.ActualParamListContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code AccessThis}
|
||||
* labeled alternative in {@link JavaliParser#identAccess}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAccessThis(JavaliParser.AccessThisContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code AccessLocalField}
|
||||
* labeled alternative in {@link JavaliParser#identAccess}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAccessLocalField(JavaliParser.AccessLocalFieldContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code AccessObjectField}
|
||||
* labeled alternative in {@link JavaliParser#identAccess}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAccessObjectField(JavaliParser.AccessObjectFieldContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code AccessLocalMethod}
|
||||
* labeled alternative in {@link JavaliParser#identAccess}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAccessLocalMethod(JavaliParser.AccessLocalMethodContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code AccessArray}
|
||||
* labeled alternative in {@link JavaliParser#identAccess}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAccessArray(JavaliParser.AccessArrayContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code AccessObjectMethod}
|
||||
* labeled alternative in {@link JavaliParser#identAccess}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitAccessObjectMethod(JavaliParser.AccessObjectMethodContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ExprBinary}
|
||||
* labeled alternative in {@link JavaliParser#expr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitExprBinary(JavaliParser.ExprBinaryContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ExprCast}
|
||||
* labeled alternative in {@link JavaliParser#expr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitExprCast(JavaliParser.ExprCastContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ExprParentheses}
|
||||
* labeled alternative in {@link JavaliParser#expr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitExprParentheses(JavaliParser.ExprParenthesesContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ExprUnary}
|
||||
* labeled alternative in {@link JavaliParser#expr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitExprUnary(JavaliParser.ExprUnaryContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ExprConstant}
|
||||
* labeled alternative in {@link JavaliParser#expr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitExprConstant(JavaliParser.ExprConstantContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code ExprIdentAccess}
|
||||
* labeled alternative in {@link JavaliParser#expr}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitExprIdentAccess(JavaliParser.ExprIdentAccessContext ctx);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package cd.frontend.parser;
|
||||
|
||||
public class ParseFailure extends RuntimeException {
|
||||
private static final long serialVersionUID = -949992757679367939L;
|
||||
public ParseFailure(int line, String string) {
|
||||
super(String.format("Parse failure on line %d: %s",
|
||||
line, string));
|
||||
}
|
||||
}
|
346
src/cd/frontend/semantic/ExprAnalyzer.java
Normal file
346
src/cd/frontend/semantic/ExprAnalyzer.java
Normal file
|
@ -0,0 +1,346 @@
|
|||
package cd.frontend.semantic;
|
||||
|
||||
import cd.frontend.semantic.SemanticAnalyzer.SemanticLocation;
|
||||
import cd.frontend.semantic.SemanticFailure.Cause;
|
||||
import cd.ir.Ast;
|
||||
import cd.ir.Ast.*;
|
||||
import cd.ir.ExprVisitor;
|
||||
import cd.ir.Symbol;
|
||||
import cd.ir.Symbol.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Semantic analyzer for {@link Expr} nodes in the pattern of a visitor. <br>
|
||||
* All methods may throw {@link SemanticFailure} if an error is discovered,
|
||||
* with the appropriate {@link Cause}. <br>
|
||||
* The current implementation returns the resulting {@link Symbol} for each expression and
|
||||
* uses the {@link ClassDecl} argument to obtain the self-reference in the {@link ThisRef} node.
|
||||
* <br> Some methods may throw a {@link RuntimeException} if they are in a
|
||||
* illegal situation, given the grammar of Javali and current implementation.
|
||||
* This signals an error in the implementation, not a user-caused error.
|
||||
* @see cd.frontend.semantic.StmtAnalyzer
|
||||
* @author Carlos Galindo
|
||||
* @author Levin Moser
|
||||
*/
|
||||
public class ExprAnalyzer extends ExprVisitor<TypeSymbol,SemanticLocation> {
|
||||
/** Reference to the main semantic analyzer, used to access the type list via
|
||||
* {@link SemanticAnalyzer#findType(String)} */
|
||||
private SemanticAnalyzer sem;
|
||||
|
||||
ExprAnalyzer(SemanticAnalyzer sem) {
|
||||
this.sem = sem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the possible semantic errors that can appear in a {@link BinaryOp} node
|
||||
* @param ast The node describing the binary operation
|
||||
* @param arg The class and method in which the operation is performed
|
||||
* @return A {@link PrimitiveTypeSymbol} of resulting type, depending on the operation
|
||||
* performed (either {@code int} or {@code boolean})
|
||||
* @throws SemanticFailure If the types of both operands aren't equal
|
||||
* @throws SemanticFailure With {@code ==} or {@code !=} operators, if no argument's type is
|
||||
* a subtype of the other
|
||||
* @throws SemanticFailure If the type of the operands doesn't match the type
|
||||
* of the operation (either {@code int} or {@code boolean}
|
||||
* @throws RuntimeException If the implementation has missed any {@link BinaryOp.BOp} type
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol binaryOp(BinaryOp ast, SemanticLocation arg) {
|
||||
TypeSymbol leftType = visit(ast.left(), arg);
|
||||
TypeSymbol rightType = visit(ast.right(), arg);
|
||||
TypeSymbol desiredType;
|
||||
TypeSymbol returnType = PrimitiveTypeSymbol.booleanType;
|
||||
switch (ast.operator) {
|
||||
case B_AND:
|
||||
case B_OR:
|
||||
desiredType = PrimitiveTypeSymbol.booleanType;
|
||||
break;
|
||||
case B_PLUS:
|
||||
case B_MINUS:
|
||||
case B_TIMES:
|
||||
case B_DIV:
|
||||
case B_MOD:
|
||||
desiredType = PrimitiveTypeSymbol.intType;
|
||||
returnType = desiredType;
|
||||
break;
|
||||
case B_LESS_THAN:
|
||||
case B_GREATER_THAN:
|
||||
case B_LESS_OR_EQUAL:
|
||||
case B_GREATER_OR_EQUAL:
|
||||
desiredType = PrimitiveTypeSymbol.intType;
|
||||
break;
|
||||
case B_EQUAL:
|
||||
case B_NOT_EQUAL:
|
||||
// Can take any pair of types that are a subtype of each other
|
||||
desiredType = null;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Missing BOp in implementation of ExprAnalyzer#binaryOp(...)");
|
||||
}
|
||||
|
||||
if (desiredType == null) {
|
||||
if (leftType.isSubtypeOf(rightType) || rightType.isSubtypeOf(leftType))
|
||||
return returnType;
|
||||
else
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Operation \"%s\" operation with incompatible types %s and %s",
|
||||
ast.operator.repr, leftType, rightType);
|
||||
} else if (leftType == rightType) {
|
||||
if (leftType == desiredType)
|
||||
return returnType;
|
||||
else
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Arguments of %s operation must be of %s type, found %s",
|
||||
ast.operator.repr, desiredType, leftType);
|
||||
} else {
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Arguments of %s operation must be of same type %s, found %s and %s",
|
||||
ast.operator.repr, desiredType, leftType, rightType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the {@code boolean} type
|
||||
* @param ast Node describing the constant
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return {@link PrimitiveTypeSymbol} representing the {@code boolean} type
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol booleanConst(BooleanConst ast, SemanticLocation arg) {
|
||||
return PrimitiveTypeSymbol.booleanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the {@code int} type (all reads in Javali result in an integer)
|
||||
* @param ast Node describing the expression
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return {@link PrimitiveTypeSymbol} representing the {@code int} type
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol builtInRead(BuiltInRead ast, SemanticLocation arg) {
|
||||
return PrimitiveTypeSymbol.intType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks possible semantic errors in a {@link Cast} node. <br>
|
||||
* Uses {@link TypeSymbol#isSubtypeOf(TypeSymbol)} to determine if the types are compatible.
|
||||
* @return The resulting type after the cast
|
||||
* @throws SemanticFailure If the destination type doesn't exist
|
||||
* @throws SemanticFailure If the types are incompatible (none is a subtype of the other)
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol cast(Cast ast, SemanticLocation arg) {
|
||||
TypeSymbol castType = sem.findType(ast.typeName);
|
||||
TypeSymbol exprType = visit(ast.arg(), arg);
|
||||
if (exprType.isSubtypeOf(castType) || castType.isSubtypeOf(exprType))
|
||||
return castType;
|
||||
else
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Type %s cannot be casted to %s, as they are unrelated", exprType, castType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks possible semantic errors in a {@link Field} node.
|
||||
* @param ast Node describing the field access
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return Field accessed, as defined in the corresponding {@link ClassSymbol}
|
||||
* @throws SemanticFailure If the field to access doesn't exist
|
||||
* @throws SemanticFailure If the expression in whose field is accessed
|
||||
* is not a {@link ClassSymbol}
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol field(Field ast, SemanticLocation arg) {
|
||||
TypeSymbol variableType = visit(ast.arg(), arg);
|
||||
if (!(variableType instanceof ClassSymbol))
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"The field of a %s variable cannot be accessed, it is not a object type", variableType);
|
||||
ClassSymbol classType = (ClassSymbol) variableType;
|
||||
VariableSymbol field = classType.getField(ast.fieldName);
|
||||
if (field == null)
|
||||
throw new SemanticFailure(Cause.NO_SUCH_FIELD,
|
||||
"The field %s doesn't exist in class %s",
|
||||
ast.fieldName, variableType);
|
||||
else
|
||||
return field.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks possible semantic errors in a {@link Index} node.
|
||||
* @param ast Node describing the index operation
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return Type of the elements of the array indexed
|
||||
* @throws SemanticFailure If the index is not an integer
|
||||
* @throws SemanticFailure If the expression indexed is not an array
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol index(Index ast, SemanticLocation arg) {
|
||||
TypeSymbol arrayType = visit(ast.left(), arg);
|
||||
TypeSymbol indexType = visit(ast.right(), arg);
|
||||
|
||||
if (indexType != PrimitiveTypeSymbol.intType)
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR, "The index must be a int, found %s", indexType);
|
||||
else if (!(arrayType instanceof ArrayTypeSymbol))
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR, "Expecting array type, found %s", arrayType);
|
||||
else
|
||||
return ((ArrayTypeSymbol) arrayType).elementType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the {@code int} type
|
||||
* @param ast Node describing the constant
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return A PrimitiveTypeSymbol for the type int
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol intConst(IntConst ast, SemanticLocation arg) {
|
||||
return PrimitiveTypeSymbol.intType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the method referenced exists in the current scope and the typing of
|
||||
* the parameters.
|
||||
* @param ast Node describing the method call
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return The return type for the method called
|
||||
* @throws SemanticFailure If the number of parameters doesn't match the declaration
|
||||
* @throws SemanticFailure If the parameters' types don't match the declaration
|
||||
* @throws SemanticFailure If the method doesn't exist
|
||||
* @throws SemanticFailure If the {@link MethodCallExpr#receiver()} is not
|
||||
* a object type (methods cannot be called on PrimitiveTypes or Arrays)
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol methodCall(MethodCallExpr ast, SemanticLocation arg) {
|
||||
TypeSymbol receiverType = visit(ast.receiver(), arg);
|
||||
// Check receiver validity
|
||||
if (!(receiverType instanceof ClassSymbol))
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR, "Expected object class, found %s", receiverType);
|
||||
// Find method symbol
|
||||
ast.sym = sem.findMethod(ast.methodName, (ClassSymbol) receiverType);
|
||||
if (ast.sym == null)
|
||||
throw new SemanticFailure(Cause.NO_SUCH_METHOD, "Method %s(...) doesn't exist", ast.methodName);
|
||||
// Compare expected with available parameters
|
||||
List<Expr> realParams = ast.argumentsWithoutReceiver();
|
||||
List<VariableSymbol> expectedParams = ast.sym.parameters;
|
||||
if (realParams.size() != expectedParams.size())
|
||||
throw new SemanticFailure(Cause.WRONG_NUMBER_OF_ARGUMENTS,
|
||||
"%s call has %d parameters, expected %d",
|
||||
ast.sym, realParams.size(), expectedParams.size());
|
||||
for (int i = 0; i < realParams.size(); i++) {
|
||||
TypeSymbol realType = visit(realParams.get(i), arg);
|
||||
TypeSymbol expectedType = expectedParams.get(i).type;
|
||||
if (!realType.isSubtypeOf(expectedType))
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR, "Parameter %d of %s of type %s, expected %s",
|
||||
i, ast.sym, realType, expectedType);
|
||||
}
|
||||
return ast.sym.returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic errors in the creation of a new object of the specified type
|
||||
* @param ast Node describing the new object expression
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return {@link ClassSymbol} corresponding to the type of the new object
|
||||
* @throws SemanticFailure If the type referenced doesn't exist
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol newObject(NewObject ast, SemanticLocation arg) {
|
||||
return sem.findType(ast.typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic errors in the creation of a new array of the specified type and size
|
||||
* @param ast Node describing the new array expression
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return ArrayTypeSymbol of the corresponding type
|
||||
* @throws SemanticFailure If the array type doesn't exist
|
||||
* @throws SemanticFailure If the expression indicating the size of the array is not an {@code int}
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol newArray(NewArray ast, SemanticLocation arg) {
|
||||
// Type exists (if it does, it is guaranteed by the grammar to be a ArrayTypeSymbol)
|
||||
ArrayTypeSymbol type = (ArrayTypeSymbol) sem.findType(ast.typeName);
|
||||
// Array length must be of type int
|
||||
TypeSymbol indexType = visit(ast.arg(), arg);
|
||||
if (indexType != PrimitiveTypeSymbol.intType)
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR, "Array size must be of type int, found %s", indexType);
|
||||
else
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the {@code null} type
|
||||
* @param ast Node describing the new object instantiation expression
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return The ClassSymbol corresponding to {@code null}
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol nullConst(NullConst ast, SemanticLocation arg) {
|
||||
return ClassSymbol.nullType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the reference to {@code this}
|
||||
* @param ast The AST node
|
||||
* @param arg Class and method in which the class reference is accessed
|
||||
* @return The VariableSymbol {@code this} from the class
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol thisRef(ThisRef ast, SemanticLocation arg) {
|
||||
return arg.classSymbol.thisSymbol.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a {@link UnaryOp} is valid semantically
|
||||
* @param ast The node describing the operation
|
||||
* @param arg Class and method in which the expression exists
|
||||
* @return The resulting type of the operation
|
||||
* @throws SemanticFailure With "{@code !}" operator, if the operand is not a {@code boolean}
|
||||
* @throws SemanticFailure With "{@code +}" or "{@code -}" operators, if the operand is not an {@code int}
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol unaryOp(UnaryOp ast, SemanticLocation arg) {
|
||||
TypeSymbol argType = visit(ast.arg(), arg);
|
||||
|
||||
TypeSymbol desiredType = PrimitiveTypeSymbol.intType;
|
||||
if (ast.operator.equals(Ast.UnaryOp.UOp.U_BOOL_NOT))
|
||||
desiredType = PrimitiveTypeSymbol.booleanType;
|
||||
|
||||
if (argType == desiredType)
|
||||
return desiredType;
|
||||
else
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Operator %s expected operand of type %s, found %s",
|
||||
ast.operator.repr, desiredType, argType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the variable referenced by the {@link Var} node exists
|
||||
* in the current scope, either as local variable, method parameter or field
|
||||
* (including inherited fields)
|
||||
* <br> In the process, the {@link Var} node is linked to the
|
||||
* {@link VariableSymbol}
|
||||
* @param ast Node describing the variable access
|
||||
* @param arg Class and method that define the current scope in which the
|
||||
* variable is looked for
|
||||
* @return The {@link VariableSymbol} corresponding to the variable
|
||||
* @throws SemanticFailure If the variable doesn't exist in the current scope
|
||||
*/
|
||||
@Override
|
||||
public TypeSymbol var(Var ast, SemanticLocation arg) {
|
||||
// Local variable
|
||||
ast.sym = arg.getMethod().locals.get(ast.name);
|
||||
if (ast.sym != null)
|
||||
return ast.sym.type;
|
||||
// Method parameter
|
||||
for(VariableSymbol var : arg.getMethod().parameters)
|
||||
if (var.name.equals(ast.name))
|
||||
return (ast.sym = var).type;
|
||||
// Class field (or field of a superclass)
|
||||
ast.sym = arg.classSymbol.getField(ast.name);
|
||||
if (ast.sym != null)
|
||||
return ast.sym.type;
|
||||
// The variable cannot be found in any known scope
|
||||
throw new SemanticFailure(Cause.NO_SUCH_VARIABLE, "Variable %s not found", ast.name);
|
||||
}
|
||||
}
|
235
src/cd/frontend/semantic/SemanticAnalyzer.java
Normal file
235
src/cd/frontend/semantic/SemanticAnalyzer.java
Normal file
|
@ -0,0 +1,235 @@
|
|||
package cd.frontend.semantic;
|
||||
|
||||
import cd.Main;
|
||||
import cd.frontend.semantic.SemanticFailure.Cause;
|
||||
import cd.ir.Ast;
|
||||
import cd.ir.Ast.ClassDecl;
|
||||
import cd.ir.Ast.MethodDecl;
|
||||
import cd.ir.Symbol;
|
||||
import cd.ir.Symbol.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SemanticAnalyzer {
|
||||
/** Name of the main class of the program, containing the start point for its execution */
|
||||
public static final String MAIN_CLASS_NAME = "Main";
|
||||
/** Name of the start point method inside the main class, with signature {@code void MAIN_METHOD_NAME()} */
|
||||
public static final String MAIN_METHOD_NAME = "main";
|
||||
|
||||
/** Reference to main method, for main class and list of types */
|
||||
public final Main main;
|
||||
/** Statement analyzer, entrypoint for the method body analysis */
|
||||
public final StmtAnalyzer sa = new StmtAnalyzer(this);
|
||||
/** For analyzing expressions, used by the StmtAnalyzer when an expression is found */
|
||||
public final ExprAnalyzer ea = new ExprAnalyzer(this);
|
||||
|
||||
private List<ClassDecl> classDecls;
|
||||
|
||||
public SemanticAnalyzer(Main main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entrypoint for semantic analysis, will check that a list of classes is correct semantically
|
||||
* @param classDeclList List of classes that form the Javali program
|
||||
* @throws SemanticFailure If any semantic error is found
|
||||
*/
|
||||
public void check(List<ClassDecl> classDeclList) throws SemanticFailure {
|
||||
this.classDecls = classDeclList;
|
||||
checkCircularInheritance(classDecls);
|
||||
// Built-in type generation
|
||||
main.allTypeSymbols = new ArrayList<>();
|
||||
addBuiltInTypes(main.allTypeSymbols);
|
||||
// Main semantic analysis
|
||||
for (ClassDecl classDecl : classDecls)
|
||||
sa.visit(classDecl, null);
|
||||
// Find entrypoint Main and Main.main(...)
|
||||
findMainClass();
|
||||
findEntrypoint(main.mainType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the basic types that exist in any Javali program by default
|
||||
* @param list Type list to which the types must be added
|
||||
*/
|
||||
private void addBuiltInTypes(List<TypeSymbol> list) {
|
||||
// Add primitive types
|
||||
list.add(PrimitiveTypeSymbol.booleanType);
|
||||
list.add(PrimitiveTypeSymbol.intType);
|
||||
list.add(PrimitiveTypeSymbol.voidType);
|
||||
// Add basic class types
|
||||
list.add(ClassSymbol.objectType);
|
||||
list.add(ClassSymbol.nullType);
|
||||
// Add arrays of primitive and class types
|
||||
list.add(new ArrayTypeSymbol(PrimitiveTypeSymbol.intType));
|
||||
list.add(new ArrayTypeSymbol(PrimitiveTypeSymbol.booleanType));
|
||||
list.add(new ArrayTypeSymbol(ClassSymbol.objectType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the {@code Main} class in a Javali program
|
||||
* @throws SemanticFailure If there is no such class
|
||||
*/
|
||||
private void findMainClass() {
|
||||
for (TypeSymbol type : main.allTypeSymbols)
|
||||
if (type.name.equals(MAIN_CLASS_NAME))
|
||||
main.mainType = (ClassSymbol) type;
|
||||
if (main.mainType == null)
|
||||
throw new SemanticFailure(Cause.INVALID_START_POINT,
|
||||
"Can't find class called \"%s\"", MAIN_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the entrypoint for the Javali program
|
||||
* @param mainType {@code Main} class of the program, where the entrypoint should be.
|
||||
* @throws SemanticFailure If there is no such entrypoint, of it has incorrect return
|
||||
* value or parameters.
|
||||
*/
|
||||
private void findEntrypoint(ClassSymbol mainType) {
|
||||
MethodSymbol mainMethod = mainType.getMethod(MAIN_METHOD_NAME);
|
||||
if (mainMethod == null)
|
||||
throw new SemanticFailure(Cause.INVALID_START_POINT,
|
||||
"No method called \"%s\" in %s class", MAIN_METHOD_NAME, MAIN_CLASS_NAME);
|
||||
else if (mainMethod.returnType != PrimitiveTypeSymbol.voidType)
|
||||
throw new SemanticFailure(Cause.INVALID_START_POINT,
|
||||
"Method %s.%s(...) returns %s, expected void",
|
||||
MAIN_CLASS_NAME, MAIN_METHOD_NAME, mainMethod.returnType);
|
||||
else if (!mainMethod.parameters.isEmpty())
|
||||
throw new SemanticFailure(Cause.INVALID_START_POINT,
|
||||
"Method %s.%s(...) must have no arguments, found %d",
|
||||
MAIN_CLASS_NAME, MAIN_METHOD_NAME, mainMethod.parameters.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the requested type in the list of types. If not found, will try to read the remaining
|
||||
* {@link ClassDecl} nodes to find the desired type.
|
||||
* @param type Name of the type. Can be built-in, user-declared, or an array type.
|
||||
* @return The TypeSymbol object associated with the type (no new symbol is created, only looked up from
|
||||
* the general list).
|
||||
* @throws SemanticFailure If the type doesn't exist
|
||||
*/
|
||||
public TypeSymbol findType(String type) {
|
||||
// Option 1: type already exists
|
||||
for (TypeSymbol symbol : main.allTypeSymbols)
|
||||
if (type.equals(symbol.name))
|
||||
return symbol;
|
||||
// Option 2: type is declared by user but hasn't been visited yet
|
||||
String noArrayType = type;
|
||||
if (type.contains("[]")) // To find the type of an array, remove "[]" and search for the name
|
||||
noArrayType = type.substring(0, type.indexOf("[]"));
|
||||
for (ClassDecl classDecl : classDecls)
|
||||
if (classDecl.name.equals(noArrayType)) {
|
||||
sa.visit(classDecl, null);
|
||||
return findType(type); // Will use option 1
|
||||
}
|
||||
// Option 3: the type doesn't exist
|
||||
throw new SemanticFailure(Cause.NO_SUCH_TYPE, "Type %s doesn't exist", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the requested method in the corresponding class. If not found, will try to find it as
|
||||
* {@link MethodDecl} inside the {@link ClassDecl}. Will also look in superclasses of {@code receiverType}.
|
||||
* @param methodName Name of the method that is being looked up
|
||||
* @param receiverType Class in which the method must be found
|
||||
* @return The method symbol (not created, but looked up from the class' method list.
|
||||
*/
|
||||
public MethodSymbol findMethod(String methodName, ClassSymbol receiverType) {
|
||||
// Option 0: looking for methods in Object or null class (that has no methods or associated ast)
|
||||
if (receiverType == ClassSymbol.objectType || receiverType == ClassSymbol.nullType)
|
||||
throw new SemanticFailure(Cause.NO_SUCH_METHOD, "Type %s has no methods", receiverType);
|
||||
// Option 1: method has already been discovered
|
||||
MethodSymbol res = receiverType.methods.get(methodName);
|
||||
if (res != null) return res;
|
||||
// Option 2: method exists but hasn't been read yet (look in superclasses)
|
||||
assert receiverType.ast != null;
|
||||
for (MethodDecl methodDecl : receiverType.ast.methods()) {
|
||||
if (methodDecl.name.equals(methodName)) {
|
||||
sa.visit(methodDecl, new SemanticLocation(receiverType));
|
||||
return findMethod(methodName, receiverType); // Will use Option 1
|
||||
}
|
||||
}
|
||||
// Option 3: method exists in superclass
|
||||
res = findMethod(methodName, receiverType.superClass);
|
||||
if (res != null) return res;
|
||||
// Option 4: method doesn't exist
|
||||
throw new SemanticFailure(Cause.NO_SUCH_METHOD, "Method %s of class %s doesn't exist",
|
||||
methodName, receiverType.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively checks for circular inheritance <br>
|
||||
* This check is done with the Strings extracted from the list of class declarations, as to perform it
|
||||
* before the type check (which can be difficult to deal with given undiscovered circular inheritance), in order
|
||||
* to avoid methods such as {@link ClassSymbol#getMethod(String)} or {@link ClassSymbol#getField(String)}, which
|
||||
* are recursive by nature, throw a {@link StackOverflowError}.
|
||||
* @param classDecls List of class declarations to check against
|
||||
* @throws SemanticFailure If circular inheritance is found
|
||||
* @throws SemanticFailure If any type inherited by a class doesn't exist (guaranteed to be a class type by
|
||||
* the language grammar).
|
||||
*/
|
||||
public void checkCircularInheritance(List<ClassDecl> classDecls) {
|
||||
Map<String, String> inherits = new HashMap<>();
|
||||
for (ClassDecl classDecl : classDecls)
|
||||
inherits.put(classDecl.name, classDecl.superClass);
|
||||
for (ClassDecl classDecl : classDecls)
|
||||
checkCircularInheritance(classDecl.name, new HashSet<>(), inherits);
|
||||
}
|
||||
|
||||
private void checkCircularInheritance(String className, Set<String> set, Map<String, String> inherits) {
|
||||
if (className.equals("Object")) return;
|
||||
if (!set.add(className))
|
||||
throw new SemanticFailure(Cause.CIRCULAR_INHERITANCE,
|
||||
"Class %s has itself as superclass", className);
|
||||
if (inherits.get(className) != null)
|
||||
checkCircularInheritance(inherits.get(className), set, inherits);
|
||||
else
|
||||
throw new SemanticFailure(Cause.NO_SUCH_TYPE, "Class %s doesn't exist", className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class that stores the position of a statement or expression being visited, by providing a link
|
||||
* to the method and class symbols. This is useful when visiting variable nodes, method calls
|
||||
* and {@code this} references. <br>
|
||||
* When entering and existing the body of a method, {@link SemanticLocation#beginMethod(MethodSymbol)} and
|
||||
* {@link SemanticLocation#endMethod()} are used to set and unset the methodSymbol field.
|
||||
*/
|
||||
public static class SemanticLocation {
|
||||
private MethodSymbol methodSymbol;
|
||||
public final ClassSymbol classSymbol;
|
||||
|
||||
/**
|
||||
* Creates a semantic location that points to the {@code classSymbol}
|
||||
*/
|
||||
SemanticLocation(ClassSymbol classSymbol) {
|
||||
this(classSymbol, null);
|
||||
}
|
||||
|
||||
private SemanticLocation(ClassSymbol classSymbol, MethodSymbol methodSymbol) {
|
||||
assert classSymbol != null;
|
||||
this.methodSymbol = methodSymbol;
|
||||
this.classSymbol = classSymbol;
|
||||
}
|
||||
|
||||
public MethodSymbol getMethod() {
|
||||
return methodSymbol;
|
||||
}
|
||||
|
||||
public boolean isInMethod() {
|
||||
return methodSymbol != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for methodSymbol
|
||||
*/
|
||||
public void beginMethod(MethodSymbol methodSymbol) {
|
||||
this.methodSymbol = methodSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsetter for methodSymbol
|
||||
*/
|
||||
public void endMethod() {
|
||||
this.methodSymbol = null;
|
||||
}
|
||||
}
|
||||
}
|
127
src/cd/frontend/semantic/SemanticFailure.java
Normal file
127
src/cd/frontend/semantic/SemanticFailure.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
package cd.frontend.semantic;
|
||||
|
||||
/**
|
||||
* Thrown by the semantic checker when a semantic error is detected
|
||||
* in the user's program. */
|
||||
public class SemanticFailure extends RuntimeException {
|
||||
private static final long serialVersionUID = 5375946759285719123L;
|
||||
|
||||
public enum Cause {
|
||||
/**
|
||||
* Caused by a nested method being found. Those are not
|
||||
* supported.
|
||||
*/
|
||||
NESTED_METHODS_UNSUPPORTED,
|
||||
|
||||
/**
|
||||
* Caused by an assignment to either a final field, {@code this},
|
||||
* or some other kind of expression which cannot be assigned to.
|
||||
* <b>Not</b> used for type errors in assignments, which fall
|
||||
* under {@link #TYPE_ERROR}. */
|
||||
NOT_ASSIGNABLE,
|
||||
|
||||
/** The value of a final field is not a compile-time constant */
|
||||
NOT_A_CONSTANT_EXPR,
|
||||
|
||||
/** Two variables, fields, methods, or classes with the same name
|
||||
* were declared in the same scope */
|
||||
DOUBLE_DECLARATION,
|
||||
|
||||
/** A field was accessed that does not exist */
|
||||
NO_SUCH_FIELD,
|
||||
|
||||
/** A method was called that does not exist */
|
||||
NO_SUCH_METHOD,
|
||||
|
||||
/**
|
||||
* A variable or other identifier was used in a method
|
||||
* body which has no corresponding declaration */
|
||||
NO_SUCH_VARIABLE,
|
||||
|
||||
/**
|
||||
* A method with a return type is missing a return statement among one of its paths */
|
||||
MISSING_RETURN,
|
||||
|
||||
/**
|
||||
* Can occur in many contents:
|
||||
* <ul>
|
||||
* <li> Assignment to a variable from an expression of wrong type
|
||||
* <li> A parameter in a method invocation had the wrong type
|
||||
* <li> A condition of a while loop or if statement was not boolean
|
||||
* <li> A non-array was indexed (i.e., a[i] where a is not an array)
|
||||
* <li> The index was not an int (i.e., a[i] where i is not an int)
|
||||
* <li> Arithmetic operators (+,-,etc) used with non-int type
|
||||
* <li> Boolean operators (!,&&,||,etc) used with non-boolean type
|
||||
* <li> Method or field accessed on non-object type
|
||||
* <li> {@code write()} is used with non-int argument
|
||||
* <li> An invalid cast was detected (i.e., a cast to a type that
|
||||
* is not a super- or sub-type of the original type).
|
||||
* <li> The size of an array in a new expression was not an
|
||||
* int (i.e., new A[i] where i is not an int)
|
||||
* </ul>
|
||||
*/
|
||||
TYPE_ERROR,
|
||||
|
||||
/**
|
||||
* A class is its own super class
|
||||
*/
|
||||
CIRCULAR_INHERITANCE,
|
||||
|
||||
/**
|
||||
* One of the following:
|
||||
* <ul>
|
||||
* <li>No class {@code Main}
|
||||
* <li>Class {@code Main} does not have a method {@code main()}
|
||||
* <li>The method {@code main} has > 0 parameters.
|
||||
* <li>The method {@code main} has a non-void return type.
|
||||
* </ul>
|
||||
*/
|
||||
INVALID_START_POINT,
|
||||
|
||||
/**
|
||||
* A class {@code Object} was defined. This class is implicitly
|
||||
* defined and cannot be defined explicitly.
|
||||
*/
|
||||
OBJECT_CLASS_DEFINED,
|
||||
|
||||
/**
|
||||
* A type name was found for which no class declaration exists.
|
||||
* This can occur in many contexts:
|
||||
* <ul>
|
||||
* <li>The extends clause on a class declaration.
|
||||
* <li>A cast.
|
||||
* <li>A new expression.
|
||||
* </ul>
|
||||
*/
|
||||
NO_SUCH_TYPE,
|
||||
|
||||
/**
|
||||
* The parameters of an overridden method have different types
|
||||
* from the base method, there is a different
|
||||
* number of parameters, or the return value is different.
|
||||
*/
|
||||
INVALID_OVERRIDE,
|
||||
|
||||
/** A method was called with the wrong number of arguments */
|
||||
WRONG_NUMBER_OF_ARGUMENTS,
|
||||
|
||||
/**
|
||||
* Indicates the use of a local variable that may not have been
|
||||
* initialized (ACD only).
|
||||
*/
|
||||
POSSIBLY_UNINITIALIZED,
|
||||
}
|
||||
|
||||
public final Cause cause;
|
||||
|
||||
public SemanticFailure(Cause cause) {
|
||||
super(cause.name());
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public SemanticFailure(Cause cause, String format, Object... args) {
|
||||
super(String.format(format, args));
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
}
|
353
src/cd/frontend/semantic/StmtAnalyzer.java
Normal file
353
src/cd/frontend/semantic/StmtAnalyzer.java
Normal file
|
@ -0,0 +1,353 @@
|
|||
package cd.frontend.semantic;
|
||||
|
||||
import cd.frontend.semantic.SemanticAnalyzer.SemanticLocation;
|
||||
import cd.frontend.semantic.SemanticFailure.Cause;
|
||||
import cd.ir.Ast;
|
||||
import cd.ir.Ast.*;
|
||||
import cd.ir.AstVisitor;
|
||||
import cd.ir.Symbol;
|
||||
import cd.ir.Symbol.*;
|
||||
import cd.ir.Symbol.VariableSymbol.Kind;
|
||||
|
||||
/**
|
||||
* Semantic analyzer for {@link Ast} nodes in the pattern of a visitor. <br>
|
||||
* All methods may throw {@link SemanticFailure} if an error is discovered,
|
||||
* with the appropriate {@link Cause} and a short explanation to give some context
|
||||
* to the user. <br>
|
||||
* The current implementation employs the {@link Symbol} returned to signal a
|
||||
* statement, or group of them that contain a unconditional return (or return in both
|
||||
* branches of a {@link IfElse} node. The type is checked by
|
||||
* {@link StmtAnalyzer#returnStmt(ReturnStmt, SemanticLocation)} and the existence, by
|
||||
* {@link StmtAnalyzer#methodDecl(MethodDecl, SemanticLocation)} <br>
|
||||
* Uses the {@link SemanticLocation} argument to give context to each statement and
|
||||
* expression visited, so that they may access variables, fields and methods.
|
||||
* @see ExprAnalyzer
|
||||
* @author Carlos Galindo
|
||||
* @author Levin Moser
|
||||
*/
|
||||
public class StmtAnalyzer extends AstVisitor<Symbol,SemanticLocation> {
|
||||
/**
|
||||
* Reference to the main semantic analyzer <br>
|
||||
* Needed to access {@link SemanticAnalyzer#findType(String)} and the
|
||||
* {@link ExprAnalyzer}
|
||||
*/
|
||||
private SemanticAnalyzer sa;
|
||||
|
||||
StmtAnalyzer(SemanticAnalyzer sa) {
|
||||
this.sa = sa;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks semantic errors in a {@link Assign} node
|
||||
* @param ast The node containing all the information
|
||||
* @param arg The class and method in which the statement takes place
|
||||
* @return {@code null} (No return can occur in an assigment statement)
|
||||
* @throws SemanticFailure If the right-hand side is not a subtype of the left-hand side
|
||||
* @throws SemanticFailure If the left-hand side is a method call or a {@code this} reference
|
||||
*/
|
||||
@Override
|
||||
public Symbol assign(Assign ast, SemanticLocation arg) {
|
||||
TypeSymbol right = sa.ea.visit(ast.right(), arg);
|
||||
TypeSymbol left = sa.ea.visit(ast.left(), arg);
|
||||
if (!right.isSubtypeOf(left))
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"In assignment, %s is not a subtype of %s", right, left);
|
||||
// Only variables, fields and array dereferences are valid as left-hand side
|
||||
if (ast.left() instanceof Var)
|
||||
return null;
|
||||
if (ast.left() instanceof Field)
|
||||
return null;
|
||||
if (ast.left() instanceof Index)
|
||||
return null;
|
||||
String leftExprType;
|
||||
if (ast.left() instanceof MethodCallExpr)
|
||||
leftExprType = "method call";
|
||||
else if (ast.left() instanceof ThisRef)
|
||||
leftExprType = "this reference";
|
||||
else
|
||||
throw new RuntimeException("Missing valid or invalid left-hand side of assignment, check grammar");
|
||||
throw new SemanticFailure(Cause.NOT_ASSIGNABLE,
|
||||
"Left-hand side of assignment must be field, var or index, found %s", leftExprType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a possible error in a {@link BuiltInWrite} AST node.
|
||||
* @param ast The node containing all the information
|
||||
* @param arg The class and method in which the statement takes place
|
||||
* @return {@code null} (No return statement can happen inside a write)
|
||||
* @throws SemanticFailure If the type of the expression to write is not integer
|
||||
*/
|
||||
@Override
|
||||
public Symbol builtInWrite(BuiltInWrite ast, SemanticLocation arg) {
|
||||
TypeSymbol type = sa.ea.visit(ast.arg(), arg);
|
||||
if (type != PrimitiveTypeSymbol.intType)
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Argument of write function must be an int, found %s", type);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a class declaration and all contained fields and methods for semantic errors. <br>
|
||||
* Will add itself and its corresponding array type to the types list.
|
||||
* @param ast The node describing the class declaration
|
||||
* @param arg {@code null}, as nested classes aren't permitted by the Javali grammar
|
||||
* @return {@code null} (no need to check return types)
|
||||
* @throws SemanticFailure If the type of the class already exists
|
||||
* @throws SemanticFailure If the name of the class is Object (base class)
|
||||
* @throws SemanticFailure If the superclass is not defined in the Javali program
|
||||
*/
|
||||
@Override
|
||||
public Symbol classDecl(ClassDecl ast, SemanticLocation arg) {
|
||||
if (ast.sym != null) return null; // Class already visited
|
||||
|
||||
// Generate first the symbol and link it to the ast node
|
||||
ast.sym = new ClassSymbol(ast);
|
||||
|
||||
// No class can be named Object
|
||||
if (ast.name.equals(ClassSymbol.objectType.name))
|
||||
throw new SemanticFailure(Cause.OBJECT_CLASS_DEFINED, "The %s class cannot be redefined", ast.name);
|
||||
|
||||
// All classes have unique names
|
||||
for (TypeSymbol type : sa.main.allTypeSymbols)
|
||||
if (type.name.equals(ast.sym.name))
|
||||
throw new SemanticFailure(Cause.DOUBLE_DECLARATION, "Another class exists with the name %s", type);
|
||||
|
||||
// Add basic and array type to typeList (this is the only method that generates
|
||||
// a ClassSymbol or ArrayTypeSymbol)
|
||||
sa.main.allTypeSymbols.add(ast.sym);
|
||||
sa.main.allTypeSymbols.add(new ArrayTypeSymbol(ast.sym));
|
||||
|
||||
// The superclass exists (will visit other classes to look it up)
|
||||
ast.sym.superClass = (ClassSymbol) sa.findType(ast.superClass);
|
||||
|
||||
// Visit children (fields and methods)
|
||||
SemanticLocation thisClass = new SemanticLocation(ast.sym);
|
||||
for (VarDecl varDecl : ast.fields())
|
||||
ast.sym.fields.put(varDecl.name, (VariableSymbol) visit(varDecl, thisClass));
|
||||
for (MethodDecl methodDecl : ast.methods())
|
||||
visit(methodDecl, thisClass);
|
||||
|
||||
return ast.sym;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic correctness of a {@link MethodDecl} node, regarding both the method's
|
||||
* signature and its body. <br>
|
||||
* For the declaration of local variables of the method, the underlying
|
||||
* {@link Seq} node is not visited, as to keep the logic in
|
||||
* {@link StmtAnalyzer#seq(Seq, SemanticLocation)} simpler, and only related to
|
||||
* the accumulation of the return paths.
|
||||
* @param ast The node describing the method declaration
|
||||
* @param arg The class the method is being declared in
|
||||
* @return {@code null} (no need to check return types)
|
||||
* @throws SemanticFailure If multiple local variables share the same name
|
||||
* @throws SemanticFailure If there is a return type but no return statement in all paths
|
||||
* @throws SemanticFailure If the method is overloaded
|
||||
* @throws SemanticFailure If the method overrides another incorrectly
|
||||
* (mismatched parameter number, type or return type)
|
||||
* @throws SemanticFailure If the return type doesn't exist
|
||||
*/
|
||||
@Override
|
||||
public Symbol methodDecl(MethodDecl ast, SemanticLocation arg) {
|
||||
if (ast.sym != null) return null; // Already visited
|
||||
ast.sym = new MethodSymbol(ast);
|
||||
arg.beginMethod(ast.sym); // Modify the location to include the method symbol
|
||||
|
||||
// Check overloading (none is permitted)
|
||||
if (arg.classSymbol.methods.get(ast.name) != null)
|
||||
throw new SemanticFailure(Cause.DOUBLE_DECLARATION,
|
||||
"Another method exists with the name %s in class %s, overloading is not permitted",
|
||||
ast.name, arg);
|
||||
|
||||
// Check return type
|
||||
ast.sym.returnType = sa.findType(ast.returnType);
|
||||
|
||||
// Check params type and generate VariableSymbols
|
||||
assert ast.argumentNames.size() == ast.argumentTypes.size(); // This should be guaranteed by parser
|
||||
for (int i = 0; i < ast.argumentNames.size(); i++) {
|
||||
// check for repeated param name
|
||||
for (VariableSymbol var : ast.sym.parameters)
|
||||
if (var.name.equals(ast.argumentNames.get(i)))
|
||||
throw new SemanticFailure(Cause.DOUBLE_DECLARATION,
|
||||
"There are two parameters named %s in method %s", var, ast.sym);
|
||||
// add to sym param list
|
||||
ast.sym.parameters.add(new VariableSymbol(
|
||||
ast.argumentNames.get(i),
|
||||
sa.findType(ast.argumentTypes.get(i)),
|
||||
Kind.PARAM));
|
||||
}
|
||||
|
||||
// Check override (only possible if parameters and return type match)
|
||||
MethodSymbol overridden = arg.classSymbol.getMethod(ast.name);
|
||||
if (overridden != null) {
|
||||
// Return value must be the same
|
||||
if (overridden.returnType != ast.sym.returnType)
|
||||
throw new SemanticFailure(Cause.INVALID_OVERRIDE,
|
||||
"Overridden methods must share return type, expected %s, found %s",
|
||||
overridden.returnType, ast.sym.returnType);
|
||||
// Number of parameters must be the same
|
||||
if (overridden.parameters.size() != ast.sym.parameters.size())
|
||||
throw new SemanticFailure(Cause.INVALID_OVERRIDE,
|
||||
"Overridden methods must have the same number of parameters, expected %d, found %d",
|
||||
overridden.parameters.size(), ast.sym.parameters.size());
|
||||
// Types must match for all parameters
|
||||
for (int i = 0; i < ast.sym.parameters.size(); i++)
|
||||
if (overridden.parameters.get(i).type != ast.sym.parameters.get(i).type)
|
||||
throw new SemanticFailure(Cause.INVALID_OVERRIDE,
|
||||
"Overridden methods must match parameters type, expected %s, found %s for parameter %d",
|
||||
overridden.parameters.get(i).type, ast.sym.parameters.get(i).type, i);
|
||||
}
|
||||
|
||||
// Check all local variables
|
||||
for (Ast decl : ast.decls().children()) {
|
||||
VarDecl varDecl = (VarDecl) decl;
|
||||
VariableSymbol varSymbol = (VariableSymbol) visit(varDecl, arg);
|
||||
ast.sym.locals.put(varDecl.name, varSymbol);
|
||||
}
|
||||
// Check statements and return type
|
||||
Symbol returnSymbol = visit(ast.body(), arg);
|
||||
if (returnSymbol == null && ast.sym.returnType != PrimitiveTypeSymbol.voidType) {
|
||||
throw new SemanticFailure(Cause.MISSING_RETURN,
|
||||
"Method %s missing return statement", ast.sym);
|
||||
}
|
||||
|
||||
// Add method to class Symbol node
|
||||
arg.classSymbol.methods.put(ast.name, ast.sym);
|
||||
|
||||
arg.endMethod();
|
||||
return ast.sym;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic errors in a {@link VarDecl} node. It can either receive a local variable
|
||||
* or a class field.
|
||||
* @param ast Node containing the type and name for the variable
|
||||
* @param arg Class [and method] in which the variable is being declared
|
||||
* @return {@link VariableSymbol} representing the variable
|
||||
* @throws SemanticFailure If the variable has already been declared in this class
|
||||
* (hiding a field from a superclass is allowed)
|
||||
* @throws SemanticFailure If the type of the variable doesn't exist
|
||||
* @throws SemanticFailure If the local variable has already been declared
|
||||
*/
|
||||
@Override
|
||||
public Symbol varDecl(VarDecl ast, SemanticLocation arg) {
|
||||
if (arg.isInMethod()) { // Checks for local variable
|
||||
if (arg.getMethod().locals.get(ast.name) != null)
|
||||
throw new SemanticFailure(Cause.DOUBLE_DECLARATION,
|
||||
"Variable %s is already declared as a variable", ast.name);
|
||||
for (VariableSymbol var : arg.getMethod().parameters)
|
||||
if (var.name.equals(ast.name))
|
||||
throw new SemanticFailure(Cause.DOUBLE_DECLARATION,
|
||||
"Variable %s is already declared as a parameter", ast.name);
|
||||
} else { // Checks for field variable
|
||||
if (arg.classSymbol.fields.get(ast.name) != null)
|
||||
throw new SemanticFailure(Cause.DOUBLE_DECLARATION,
|
||||
"Class %s cannot have more than one variable with the same name (%s)", arg, ast.name);
|
||||
}
|
||||
ast.sym = new VariableSymbol(
|
||||
ast.name,
|
||||
sa.findType(ast.type), // Type check included here
|
||||
arg.isInMethod() ? Kind.FIELD : Kind.LOCAL);
|
||||
return ast.sym;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic errors in a {@link IfElse} node
|
||||
* @param ast Contains all the information regarding the condition and if/else bodies
|
||||
* @param arg The class and method in whose body the if statement exists
|
||||
* @return The return value if both branches have one, or {@code null} otherwise
|
||||
* @throws SemanticFailure If the condition is not of boolean type
|
||||
*/
|
||||
@Override
|
||||
public Symbol ifElse(IfElse ast, SemanticLocation arg) {
|
||||
TypeSymbol condType = sa.ea.visit(ast.condition(), arg);
|
||||
if (condType != PrimitiveTypeSymbol.booleanType)
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR, "Condition of if must be int, found %s", condType);
|
||||
Symbol then = visit(ast.then(), arg);
|
||||
Symbol otherwise = visit(ast.otherwise(), arg);
|
||||
|
||||
if (then != null && otherwise != null)
|
||||
return then;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic errors in a {@link ReturnStmt} node
|
||||
* @param ast Contains all information about the return statement
|
||||
* @param arg The class and method in which this statement takes place
|
||||
* @return Type of the underlying expression, to be returned by the method
|
||||
* @throws SemanticFailure If the return type is not a subtype of the method signature's return type
|
||||
* @throws SemanticFailure If the method does return a non-void but the return statement has no
|
||||
* expression to return
|
||||
*/
|
||||
@Override
|
||||
public Symbol returnStmt(ReturnStmt ast, SemanticLocation arg) {
|
||||
if (ast.arg() != null) {
|
||||
TypeSymbol returnType = sa.ea.visit(ast.arg(), arg);
|
||||
if (returnType.isSubtypeOf(arg.getMethod().returnType))
|
||||
return returnType;
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Return type of %s must be a subtype of %s, found %s",
|
||||
arg.getMethod(), arg.getMethod().returnType, returnType);
|
||||
} else {
|
||||
if (arg.getMethod().returnType != PrimitiveTypeSymbol.voidType)
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Empty return, expecting type %s or subtype", arg.getMethod().returnType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for semantic errors in a method call
|
||||
* @see ExprAnalyzer#methodCall(MethodCallExpr, SemanticLocation)
|
||||
* @return {@code null} (No return statement in this node)
|
||||
*/
|
||||
@Override
|
||||
public Symbol methodCall(MethodCall ast, SemanticLocation arg) {
|
||||
sa.ea.visit(ast.getMethodCallExpr(), arg);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all members of the {@link Seq} node are valid. <br>
|
||||
* This method will only visit sequences of statements, as the
|
||||
* sequences of variables are checked in
|
||||
* {@link StmtAnalyzer#methodDecl(MethodDecl, SemanticLocation)}, therefore
|
||||
* the logic is simpler and separated for unrelated elements of the method
|
||||
* body (all local variable declaration must come before the statements)
|
||||
* @param ast The node with the sequence of statements
|
||||
* @param arg Class and method in which this sequence exists, to be passed
|
||||
* down to visited statements
|
||||
* @return The first type returned by one of the underlying statements
|
||||
*/
|
||||
@Override
|
||||
public Symbol seq(Seq ast, SemanticLocation arg) {
|
||||
Symbol firstReturn = null;
|
||||
for (Ast aChildren : ast.children()) {
|
||||
Symbol sym = visit(aChildren, arg);
|
||||
if (sym != null && firstReturn == null)
|
||||
firstReturn = sym;
|
||||
}
|
||||
return firstReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks semantic errors in a while loop
|
||||
* @param ast Node containing all the information about the {@code while} loop
|
||||
* @param arg The class and method in which the loop exists
|
||||
* @return {@code null} (condition of the loop is not check to determine if
|
||||
* it is always accessed, therefore it cannot be treated as an unconditional return)
|
||||
* @throws SemanticFailure If the condition for the loop is not a boolean type
|
||||
*/
|
||||
@Override
|
||||
public Symbol whileLoop(WhileLoop ast, SemanticLocation arg) {
|
||||
TypeSymbol condType = sa.ea.visit(ast.condition(), arg);
|
||||
if (condType != PrimitiveTypeSymbol.booleanType)
|
||||
throw new SemanticFailure(Cause.TYPE_ERROR,
|
||||
"Condition of while loop must be int, found %s", condType);
|
||||
visit(ast.body(), arg);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,10 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import cd.ir.Symbol.ClassSymbol;
|
||||
import cd.ir.Symbol.MethodSymbol;
|
||||
import cd.ir.Symbol.TypeSymbol;
|
||||
import cd.ir.Symbol.VariableSymbol;
|
||||
import cd.util.Pair;
|
||||
import cd.util.debug.AstOneLine;
|
||||
|
||||
|
@ -56,7 +60,7 @@ public abstract class Ast {
|
|||
|
||||
/** Convenient debugging printout */
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"(%s)@%x",
|
||||
AstOneLine.toString(this),
|
||||
|
@ -73,14 +77,20 @@ public abstract class Ast {
|
|||
super(fixedCount);
|
||||
}
|
||||
|
||||
/** Type that this expression will evaluate to (computed in semantic phase). */
|
||||
public TypeSymbol type;
|
||||
|
||||
@Override
|
||||
public <R,A> R accept(AstVisitor<R, A> visitor, A arg) {
|
||||
public <R,A> R accept(AstVisitor<R, A> visitor, A arg) {
|
||||
return this.accept((ExprVisitor<R,A>)visitor, arg);
|
||||
}
|
||||
public abstract <R,A> R accept(ExprVisitor<R, A> visitor, A arg);
|
||||
|
||||
/** Copies any non-AST fields. */
|
||||
protected <E extends Expr> E postCopy(E item) {
|
||||
{
|
||||
item.type = type;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
@ -140,23 +150,23 @@ public abstract class Ast {
|
|||
* such as "1+2" or "3*4" */
|
||||
public static class BinaryOp extends LeftRightExpr {
|
||||
|
||||
public static enum BOp {
|
||||
|
||||
B_TIMES("*"),
|
||||
B_DIV("/"),
|
||||
B_MOD("%"),
|
||||
B_PLUS("+"),
|
||||
B_MINUS("-"),
|
||||
B_AND("&&"),
|
||||
B_OR("||"),
|
||||
B_EQUAL("=="),
|
||||
B_NOT_EQUAL("!="),
|
||||
B_LESS_THAN("<"),
|
||||
B_LESS_OR_EQUAL("<="),
|
||||
B_GREATER_THAN(">"),
|
||||
B_GREATER_OR_EQUAL(">=");
|
||||
|
||||
public String repr;
|
||||
public static enum BOp {
|
||||
|
||||
B_TIMES("*"),
|
||||
B_DIV("/"),
|
||||
B_MOD("%"),
|
||||
B_PLUS("+"),
|
||||
B_MINUS("-"),
|
||||
B_AND("&&"),
|
||||
B_OR("||"),
|
||||
B_EQUAL("=="),
|
||||
B_NOT_EQUAL("!="),
|
||||
B_LESS_THAN("<"),
|
||||
B_LESS_OR_EQUAL("<="),
|
||||
B_GREATER_THAN(">"),
|
||||
B_GREATER_OR_EQUAL(">=");
|
||||
|
||||
public String repr;
|
||||
private BOp(String repr) { this.repr = repr; }
|
||||
|
||||
/**
|
||||
|
@ -167,26 +177,26 @@ public abstract class Ast {
|
|||
* operator.
|
||||
*/
|
||||
public boolean isCommutative() {
|
||||
switch(this) {
|
||||
case B_PLUS:
|
||||
case B_TIMES:
|
||||
case B_AND:
|
||||
case B_OR:
|
||||
case B_EQUAL:
|
||||
case B_NOT_EQUAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
switch(this) {
|
||||
case B_PLUS:
|
||||
case B_TIMES:
|
||||
case B_AND:
|
||||
case B_OR:
|
||||
case B_EQUAL:
|
||||
case B_NOT_EQUAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public BOp operator;
|
||||
|
||||
public BinaryOp(Expr left, BOp operator, Expr right) {
|
||||
super(left, right);
|
||||
this.operator = operator;
|
||||
}
|
||||
};
|
||||
|
||||
public BOp operator;
|
||||
|
||||
public BinaryOp(Expr left, BOp operator, Expr right) {
|
||||
super(left, right);
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, A> R accept(ExprVisitor<R, A> visitor, A arg) {
|
||||
|
@ -210,6 +220,12 @@ public abstract class Ast {
|
|||
return visitor.cast(this, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <E extends Expr> E postCopy(E item) {
|
||||
((Cast)item).type = type;
|
||||
return super.postCopy(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class IntConst extends LeafExpr {
|
||||
|
@ -253,6 +269,8 @@ public abstract class Ast {
|
|||
|
||||
public final String fieldName;
|
||||
|
||||
public VariableSymbol sym;
|
||||
|
||||
public Field(Expr arg, String fieldName) {
|
||||
super(arg);
|
||||
assert arg != null && fieldName != null;
|
||||
|
@ -264,6 +282,12 @@ public abstract class Ast {
|
|||
return visitor.field(this, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <E extends Expr> E postCopy(E item) {
|
||||
((Field)item).sym = sym;
|
||||
return super.postCopy(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Index extends LeftRightExpr {
|
||||
|
@ -314,21 +338,21 @@ public abstract class Ast {
|
|||
|
||||
public static class UnaryOp extends ArgExpr {
|
||||
|
||||
public static enum UOp {
|
||||
U_PLUS("+"),
|
||||
U_MINUS("-"),
|
||||
U_BOOL_NOT("!");
|
||||
public String repr;
|
||||
public static enum UOp {
|
||||
U_PLUS("+"),
|
||||
U_MINUS("-"),
|
||||
U_BOOL_NOT("!");
|
||||
public String repr;
|
||||
private UOp(String repr) { this.repr = repr; }
|
||||
};
|
||||
|
||||
public final UOp operator;
|
||||
|
||||
public UnaryOp(UOp operator, Expr arg) {
|
||||
};
|
||||
|
||||
public final UOp operator;
|
||||
|
||||
public UnaryOp(UOp operator, Expr arg) {
|
||||
super(arg);
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <R, A> R accept(ExprVisitor<R, A> visitor, A arg) {
|
||||
return visitor.unaryOp(this, arg);
|
||||
|
@ -340,6 +364,8 @@ public abstract class Ast {
|
|||
|
||||
public String name;
|
||||
|
||||
public VariableSymbol sym;
|
||||
|
||||
/**
|
||||
* Use this constructor to build an instance of this AST
|
||||
* in the parser.
|
||||
|
@ -351,6 +377,29 @@ public abstract class Ast {
|
|||
public <R, A> R accept(ExprVisitor<R, A> visitor, A arg) {
|
||||
return visitor.var(this, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this static function to build an instance after the
|
||||
* semantic phase; it fills in the {@link #type} and {@link #sym}
|
||||
* fields.
|
||||
*/
|
||||
public static Var withSym(VariableSymbol sym) {
|
||||
Var v = new Var(sym.name);
|
||||
v.sym = sym;
|
||||
v.type = sym.type;
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <E extends Expr> E postCopy(E item) {
|
||||
((Var)item).sym = sym;
|
||||
return super.postCopy(item);
|
||||
}
|
||||
|
||||
public void setSymbol(VariableSymbol variableSymbol) {
|
||||
sym = variableSymbol;
|
||||
name = sym.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -367,6 +416,8 @@ public abstract class Ast {
|
|||
|
||||
public String methodName;
|
||||
|
||||
public MethodSymbol sym;
|
||||
|
||||
public MethodCallExpr(Expr rcvr, String methodName, List<Expr> arguments) {
|
||||
super(-1);
|
||||
assert rcvr != null && methodName != null && arguments != null;
|
||||
|
@ -588,6 +639,8 @@ public abstract class Ast {
|
|||
|
||||
public String type;
|
||||
public String name;
|
||||
public VariableSymbol sym;
|
||||
|
||||
public VarDecl(String type, String name) {
|
||||
this(0, type, name);
|
||||
}
|
||||
|
@ -631,6 +684,7 @@ public abstract class Ast {
|
|||
public String name;
|
||||
public List<String> argumentTypes;
|
||||
public List<String> argumentNames;
|
||||
public MethodSymbol sym;
|
||||
public MethodDecl(
|
||||
String returnType,
|
||||
String name,
|
||||
|
@ -672,6 +726,8 @@ public abstract class Ast {
|
|||
|
||||
public String name;
|
||||
public String superClass;
|
||||
public ClassSymbol sym;
|
||||
|
||||
public ClassDecl(
|
||||
String name,
|
||||
String superClass,
|
||||
|
|
|
@ -16,17 +16,6 @@ public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
|||
return ast.accept(this, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides {@link ExprVisitor#visitChildren(Expr, Object)} and
|
||||
* delegates to the more general {@link #visitChildren(Ast, Object)}
|
||||
* with {@link Ast} parameter. This method is final to prevent
|
||||
* overriding only one of the two versions.
|
||||
*/
|
||||
@Override
|
||||
public final R visitChildren(Expr ast, A arg) {
|
||||
return visitChildren((Ast) ast, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* A handy function which visits the children of {@code ast},
|
||||
* providing "arg" to each of them. It returns the result of
|
||||
|
@ -56,7 +45,6 @@ public class AstVisitor<R,A> extends ExprVisitor<R,A> {
|
|||
|
||||
/**
|
||||
* The default action for expressions is to call this */
|
||||
@Override
|
||||
protected R dfltExpr(Expr ast, A arg) {
|
||||
return dflt(ast, arg);
|
||||
}
|
||||
|
|
172
src/cd/ir/Symbol.java
Normal file
172
src/cd/ir/Symbol.java
Normal file
|
@ -0,0 +1,172 @@
|
|||
package cd.ir;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Symbol {
|
||||
|
||||
public final String name;
|
||||
|
||||
public static abstract class TypeSymbol extends Symbol {
|
||||
|
||||
public TypeSymbol(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public abstract boolean isReferenceType();
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the TypeSymbol is a subtype of the parameter
|
||||
* <br> The conditions are the following
|
||||
* <ul>
|
||||
* <li>Any type is a subtype of itself</li>
|
||||
* <li>Primitive types have no subtypes</li>
|
||||
* <li>Reference types are a subtype of {@code Object}</li>
|
||||
* <li>Reference types are a supertype of {@code null}</li>
|
||||
* <li>Classes can only be subtypes of other classes</li>
|
||||
* <li>Classes that inherit another are its subtypes (recursively)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public boolean isSubtypeOf(TypeSymbol sym) {
|
||||
// Any type is a subtype of itself
|
||||
if (sym == this) return true;
|
||||
// A PrimitiveType doesn't have subtypes
|
||||
if (this instanceof PrimitiveTypeSymbol || sym instanceof PrimitiveTypeSymbol)
|
||||
return false;
|
||||
// Any reference type is a subtype of Object
|
||||
if (this.isReferenceType() && sym == ClassSymbol.objectType)
|
||||
return true;
|
||||
// null is a subtype of any reference type
|
||||
if (sym.isReferenceType() && this == ClassSymbol.nullType)
|
||||
return true;
|
||||
// Class types can only be subtypes of other Class types
|
||||
// A class type is subtype of another if has inherited it
|
||||
if (sym instanceof ClassSymbol && this instanceof ClassSymbol)
|
||||
for (ClassSymbol c = (ClassSymbol) this; c != ClassSymbol.objectType; c = c.superClass)
|
||||
if (c == sym) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PrimitiveTypeSymbol extends TypeSymbol {
|
||||
|
||||
/** Symbols for the built-in primitive types */
|
||||
public static final PrimitiveTypeSymbol intType = new PrimitiveTypeSymbol("int");
|
||||
public static final PrimitiveTypeSymbol voidType = new PrimitiveTypeSymbol("void");
|
||||
public static final PrimitiveTypeSymbol booleanType = new PrimitiveTypeSymbol("boolean");
|
||||
|
||||
public PrimitiveTypeSymbol(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public boolean isReferenceType() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayTypeSymbol extends TypeSymbol {
|
||||
public final TypeSymbol elementType;
|
||||
|
||||
public ArrayTypeSymbol(TypeSymbol elementType) {
|
||||
super(elementType.name+"[]");
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public boolean isReferenceType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ClassSymbol extends TypeSymbol {
|
||||
public final Ast.ClassDecl ast;
|
||||
public ClassSymbol superClass;
|
||||
public final VariableSymbol thisSymbol =
|
||||
new VariableSymbol("this", this);
|
||||
public final Map<String, VariableSymbol> fields = new HashMap<>();
|
||||
public final Map<String, MethodSymbol> methods = new HashMap<>();
|
||||
|
||||
/** Symbols for the built-in Object and null types */
|
||||
public static final ClassSymbol nullType = new ClassSymbol("<null>");
|
||||
public static final ClassSymbol objectType = new ClassSymbol("Object");
|
||||
|
||||
public ClassSymbol(Ast.ClassDecl ast) {
|
||||
super(ast.name);
|
||||
this.ast = ast;
|
||||
}
|
||||
|
||||
/** Used to create the default {@code Object}
|
||||
* and {@code <null>} types */
|
||||
public ClassSymbol(String name) {
|
||||
super(name);
|
||||
this.ast = null;
|
||||
}
|
||||
|
||||
public boolean isReferenceType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public VariableSymbol getField(String name) {
|
||||
VariableSymbol fsym = fields.get(name);
|
||||
if (fsym == null && superClass != null)
|
||||
return superClass.getField(name);
|
||||
return fsym;
|
||||
}
|
||||
|
||||
public MethodSymbol getMethod(String name) {
|
||||
MethodSymbol msym = methods.get(name);
|
||||
if (msym == null && superClass != null)
|
||||
return superClass.getMethod(name);
|
||||
return msym;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodSymbol extends Symbol {
|
||||
|
||||
public final Ast.MethodDecl ast;
|
||||
public final Map<String, VariableSymbol> locals = new HashMap<>();
|
||||
public final List<VariableSymbol> parameters = new ArrayList<>();
|
||||
|
||||
public TypeSymbol returnType;
|
||||
|
||||
public MethodSymbol(Ast.MethodDecl ast) {
|
||||
super(ast.name);
|
||||
this.ast = ast;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name + "(...)";
|
||||
}
|
||||
}
|
||||
|
||||
public static class VariableSymbol extends Symbol {
|
||||
|
||||
public enum Kind { PARAM, LOCAL, FIELD }
|
||||
public final TypeSymbol type;
|
||||
public final Kind kind;
|
||||
|
||||
public VariableSymbol(String name, TypeSymbol type) {
|
||||
this(name, type, Kind.PARAM);
|
||||
}
|
||||
|
||||
public VariableSymbol(String name, TypeSymbol type, Kind kind) {
|
||||
super(name);
|
||||
this.type = type;
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
protected Symbol(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -160,7 +160,15 @@ public class AstOneLine {
|
|||
@Override
|
||||
public String var(Var ast, Void arg) {
|
||||
{
|
||||
return ast.name;
|
||||
if (ast.sym != null) {
|
||||
String symName = ast.sym.toString();
|
||||
if (ast.name == null || ast.name.equals(symName))
|
||||
return symName;
|
||||
|
||||
// Return something strange to warn about the mismatch here:
|
||||
return String.format("(%s!=%s)", symName, ast.name);
|
||||
} else
|
||||
return ast.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package cd.util.debug;
|
||||
|
||||
import static java.util.Collections.sort;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import cd.ir.Ast.ClassDecl;
|
||||
import cd.ir.Ast.MethodDecl;
|
||||
|
||||
class DumpUtils {
|
||||
|
||||
static final Comparator<ClassDecl> classComparator = new Comparator<ClassDecl>() {
|
||||
public int compare(ClassDecl left, ClassDecl right) {
|
||||
return left.name.compareTo(right.name);
|
||||
}
|
||||
};
|
||||
|
||||
static final Comparator<MethodDecl> methodComparator = new Comparator<MethodDecl>() {
|
||||
public int compare(MethodDecl left, MethodDecl right) {
|
||||
return left.name.compareTo(right.name);
|
||||
}
|
||||
};
|
||||
|
||||
static List<String> sortedStrings(Set<?> set) {
|
||||
List<String> strings = new ArrayList<String>();
|
||||
for(Object element : set)
|
||||
strings.add(element.toString());
|
||||
sort(strings);
|
||||
return strings;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue