Homework 3

This commit is contained in:
Carlos Galindo 2020-01-15 22:32:25 +01:00
parent bf60a078d7
commit 0afc86ceeb
Signed by: kauron
GPG key ID: 83E68706DEE119A3
129 changed files with 3163 additions and 4316 deletions

View file

@ -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";

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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));
}
}

View 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);
}
}

View 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;
}
}
}

View 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;
}
}

View 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;
}
}

View file

@ -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,

View file

@ -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
View 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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}