From 85e5f569b459206b6cc2eb28957392c681a933c2 Mon Sep 17 00:00:00 2001 From: User <> Date: Fri, 14 Jul 2017 18:27:37 +0200 Subject: [PATCH] added functions --- src/pp/s1184725/boppi/Annotations.java | 15 +- src/pp/s1184725/boppi/Basic.g4 | 3 + src/pp/s1184725/boppi/Basic.tokens | 46 +- src/pp/s1184725/boppi/BasicBaseVisitor.java | 14 + src/pp/s1184725/boppi/BasicLexer.java | 173 ++++---- src/pp/s1184725/boppi/BasicLexer.tokens | 46 +- src/pp/s1184725/boppi/BasicParser.java | 409 ++++++++++++------ src/pp/s1184725/boppi/BasicVisitor.java | 14 + src/pp/s1184725/boppi/BoppiBasicChecker.java | 136 ++++-- .../s1184725/boppi/BoppiBasicGenerator.java | 228 ++++++---- src/pp/s1184725/boppi/CachingSymbolTable.java | 101 ++++- .../boppi/DebugCachingSymbolTable.java | 57 +++ src/pp/s1184725/boppi/FunctionType.java | 94 ++++ src/pp/s1184725/boppi/SimpleType.java | 10 +- src/pp/s1184725/boppi/ToolChain.java | 4 +- src/pp/s1184725/boppi/Type.java | 12 + src/pp/s1184725/boppi/Variable.java | 15 +- src/pp/s1184725/boppi/test/CheckerTest.java | 36 ++ src/pp/s1184725/boppi/test/GeneratorTest.java | 39 ++ 19 files changed, 1046 insertions(+), 406 deletions(-) create mode 100644 src/pp/s1184725/boppi/DebugCachingSymbolTable.java create mode 100644 src/pp/s1184725/boppi/FunctionType.java create mode 100644 src/pp/s1184725/boppi/Type.java diff --git a/src/pp/s1184725/boppi/Annotations.java b/src/pp/s1184725/boppi/Annotations.java index 86a35fc..ab3c79f 100644 --- a/src/pp/s1184725/boppi/Annotations.java +++ b/src/pp/s1184725/boppi/Annotations.java @@ -1,5 +1,7 @@ package pp.s1184725.boppi; +import java.util.Stack; + import org.antlr.v4.runtime.tree.ParseTreeProperty; import pp.iloc.model.Reg; @@ -14,13 +16,18 @@ public class Annotations { */ public ParseTreeProperty registers; /** - * Maps nodes to {@link SimpleType}s. + * Maps nodes to {@link Type}s. */ - public ParseTreeProperty types; + public ParseTreeProperty types; /** * Maps nodes to {@link Variable}s. */ - public ParseTreeProperty> variables; + public ParseTreeProperty> variables; + /** + * Maps nodes to their function scope. + */ + public ParseTreeProperty> function; + public Stack> currentFunction; /** * Creates a new annotations object with empty maps. @@ -28,6 +35,8 @@ public class Annotations { public Annotations() { registers = new ParseTreeProperty<>(); types = new ParseTreeProperty<>(); + function = new ParseTreeProperty<>(); variables = new ParseTreeProperty<>(); + currentFunction = new Stack<>(); } } diff --git a/src/pp/s1184725/boppi/Basic.g4 b/src/pp/s1184725/boppi/Basic.g4 index 824e2e3..b4d0e51 100644 --- a/src/pp/s1184725/boppi/Basic.g4 +++ b/src/pp/s1184725/boppi/Basic.g4 @@ -11,6 +11,7 @@ singleExpr | BRAOPEN expr BRACLOSE #block | IN PAROPEN variable (LISTDELIM variable)* PARCLOSE #read | OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write + | variable PAROPEN expr (LISTDELIM expr)* PARCLOSE #call | IFOPEN cond=expr IFTRUE onTrue=expr (IFFALSE onFalse=expr)? IFCLOSE #if | WHILEOPEN cond=expr WHILETRUE onTrue=expr WHILECLOSE #while | op=(PLUS|MINUS|NOT) singleExpr #prefix1 @@ -20,6 +21,7 @@ singleExpr | lhs=singleExpr AND rhs=singleExpr #infix4 | lhs=singleExpr OR rhs=singleExpr #infix5 | DECLARE type IDENTIFIER #declare + | FUNCTION result=type name=IDENTIFIER PAROPEN type IDENTIFIER (LISTDELIM type IDENTIFIER)* PARCLOSE body=singleExpr #funcDeclare | variable ASSIGN singleExpr #assign | variable #var | LITERAL10 #number @@ -60,6 +62,7 @@ AND: '&&'; OR: '||'; DECLARE: 'var'; +FUNCTION: 'function'; INTTYPE: 'int'; BOOLTYPE: 'bool'; CHARTYPE: 'char'; diff --git a/src/pp/s1184725/boppi/Basic.tokens b/src/pp/s1184725/boppi/Basic.tokens index 5686c68..a139178 100644 --- a/src/pp/s1184725/boppi/Basic.tokens +++ b/src/pp/s1184725/boppi/Basic.tokens @@ -26,20 +26,21 @@ GT=25 AND=26 OR=27 DECLARE=28 -INTTYPE=29 -BOOLTYPE=30 -CHARTYPE=31 -ASSIGN=32 -COMPOUND=33 -LISTDELIM=34 -CHAR=35 -TRUE=36 -FALSE=37 -IDENTIFIER=38 -LITERAL10=39 -WHITESPACE=40 -LINECOMMENT=41 -BLOCKCOMMENT=42 +FUNCTION=29 +INTTYPE=30 +BOOLTYPE=31 +CHARTYPE=32 +ASSIGN=33 +COMPOUND=34 +LISTDELIM=35 +CHAR=36 +TRUE=37 +FALSE=38 +IDENTIFIER=39 +LITERAL10=40 +WHITESPACE=41 +LINECOMMENT=42 +BLOCKCOMMENT=43 '('=1 ')'=2 '{'=3 @@ -68,11 +69,12 @@ BLOCKCOMMENT=42 '&&'=26 '||'=27 'var'=28 -'int'=29 -'bool'=30 -'char'=31 -':='=32 -';'=33 -','=34 -'true'=36 -'false'=37 +'function'=29 +'int'=30 +'bool'=31 +'char'=32 +':='=33 +';'=34 +','=35 +'true'=37 +'false'=38 diff --git a/src/pp/s1184725/boppi/BasicBaseVisitor.java b/src/pp/s1184725/boppi/BasicBaseVisitor.java index d1b5539..c827739 100644 --- a/src/pp/s1184725/boppi/BasicBaseVisitor.java +++ b/src/pp/s1184725/boppi/BasicBaseVisitor.java @@ -102,6 +102,13 @@ public class BasicBaseVisitor extends AbstractParseTreeVisitor implements * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitInfix5(BasicParser.Infix5Context ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCall(BasicParser.CallContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * @@ -109,6 +116,13 @@ public class BasicBaseVisitor extends AbstractParseTreeVisitor implements * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitNumber(BasicParser.NumberContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFuncDeclare(BasicParser.FuncDeclareContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * diff --git a/src/pp/s1184725/boppi/BasicLexer.java b/src/pp/s1184725/boppi/BasicLexer.java index 1874d4c..9ebc2fa 100644 --- a/src/pp/s1184725/boppi/BasicLexer.java +++ b/src/pp/s1184725/boppi/BasicLexer.java @@ -20,9 +20,10 @@ public class BasicLexer extends Lexer { PAROPEN=1, PARCLOSE=2, BRAOPEN=3, BRACLOSE=4, IN=5, OUT=6, IFOPEN=7, IFTRUE=8, IFFALSE=9, IFCLOSE=10, WHILEOPEN=11, WHILETRUE=12, WHILECLOSE=13, PLUS=14, MINUS=15, NOT=16, MULTIPLY=17, DIVIDE=18, MODULO=19, LEQ=20, GTE=21, NEQ=22, - EQ=23, LT=24, GT=25, AND=26, OR=27, DECLARE=28, INTTYPE=29, BOOLTYPE=30, - CHARTYPE=31, ASSIGN=32, COMPOUND=33, LISTDELIM=34, CHAR=35, TRUE=36, FALSE=37, - IDENTIFIER=38, LITERAL10=39, WHITESPACE=40, LINECOMMENT=41, BLOCKCOMMENT=42; + EQ=23, LT=24, GT=25, AND=26, OR=27, DECLARE=28, FUNCTION=29, INTTYPE=30, + BOOLTYPE=31, CHARTYPE=32, ASSIGN=33, COMPOUND=34, LISTDELIM=35, CHAR=36, + TRUE=37, FALSE=38, IDENTIFIER=39, LITERAL10=40, WHITESPACE=41, LINECOMMENT=42, + BLOCKCOMMENT=43; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; @@ -35,25 +36,25 @@ public class BasicLexer extends Lexer { "PAROPEN", "PARCLOSE", "BRAOPEN", "BRACLOSE", "IN", "OUT", "IFOPEN", "IFTRUE", "IFFALSE", "IFCLOSE", "WHILEOPEN", "WHILETRUE", "WHILECLOSE", "PLUS", "MINUS", "NOT", "MULTIPLY", "DIVIDE", "MODULO", "LEQ", "GTE", "NEQ", "EQ", - "LT", "GT", "AND", "OR", "DECLARE", "INTTYPE", "BOOLTYPE", "CHARTYPE", - "ASSIGN", "COMPOUND", "LISTDELIM", "CHAR", "TRUE", "FALSE", "IDENTIFIER", - "LITERAL10", "WHITESPACE", "LINECOMMENT", "BLOCKCOMMENT" + "LT", "GT", "AND", "OR", "DECLARE", "FUNCTION", "INTTYPE", "BOOLTYPE", + "CHARTYPE", "ASSIGN", "COMPOUND", "LISTDELIM", "CHAR", "TRUE", "FALSE", + "IDENTIFIER", "LITERAL10", "WHITESPACE", "LINECOMMENT", "BLOCKCOMMENT" }; private static final String[] _LITERAL_NAMES = { null, "'('", "')'", "'{'", "'}'", "'read'", "'print'", "'if'", "'then'", "'else'", "'fi'", "'while'", "'do'", "'od'", "'+'", "'-'", "'!'", "'*'", "'/'", "'%'", "'<='", "'>='", "'<>'", "'=='", "'<'", "'>'", "'&&'", "'||'", - "'var'", "'int'", "'bool'", "'char'", "':='", "';'", "','", null, "'true'", - "'false'" + "'var'", "'function'", "'int'", "'bool'", "'char'", "':='", "';'", "','", + null, "'true'", "'false'" }; private static final String[] _SYMBOLIC_NAMES = { null, "PAROPEN", "PARCLOSE", "BRAOPEN", "BRACLOSE", "IN", "OUT", "IFOPEN", "IFTRUE", "IFFALSE", "IFCLOSE", "WHILEOPEN", "WHILETRUE", "WHILECLOSE", "PLUS", "MINUS", "NOT", "MULTIPLY", "DIVIDE", "MODULO", "LEQ", "GTE", - "NEQ", "EQ", "LT", "GT", "AND", "OR", "DECLARE", "INTTYPE", "BOOLTYPE", - "CHARTYPE", "ASSIGN", "COMPOUND", "LISTDELIM", "CHAR", "TRUE", "FALSE", - "IDENTIFIER", "LITERAL10", "WHITESPACE", "LINECOMMENT", "BLOCKCOMMENT" + "NEQ", "EQ", "LT", "GT", "AND", "OR", "DECLARE", "FUNCTION", "INTTYPE", + "BOOLTYPE", "CHARTYPE", "ASSIGN", "COMPOUND", "LISTDELIM", "CHAR", "TRUE", + "FALSE", "IDENTIFIER", "LITERAL10", "WHITESPACE", "LINECOMMENT", "BLOCKCOMMENT" }; public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); @@ -113,83 +114,87 @@ public class BasicLexer extends Lexer { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2,\u00fe\b\1\4\2\t"+ + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2-\u0109\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+\3"+ - "\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\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\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\13\3\13\3\13"+ - "\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\16\3\16\3\16\3\17\3\17\3\20\3\20"+ - "\3\21\3\21\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\25\3\26\3\26\3\26"+ - "\3\27\3\27\3\27\3\30\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\33\3\34"+ - "\3\34\3\34\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\37\3\37\3\37\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\'\7\'\u00d3\n\'\f\'\16\'\u00d6\13\'\3(\3(\3"+ - "(\7(\u00db\n(\f(\16(\u00de\13(\5(\u00e0\n(\3)\3)\3)\3)\3*\3*\3*\3*\7*"+ - "\u00ea\n*\f*\16*\u00ed\13*\3*\3*\3+\3+\3+\3+\7+\u00f5\n+\f+\16+\u00f8"+ - "\13+\3+\3+\3+\3+\3+\3\u00f6\2,\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*S+U,\3\2\b\5\2C\\"+ - "aac|\6\2\62;C\\aac|\3\2\63;\3\2\62;\5\2\13\f\17\17\"\"\4\2\f\f\17\17\2"+ - "\u0102\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\2"+ - "G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3"+ - "\2\2\2\2U\3\2\2\2\3W\3\2\2\2\5Y\3\2\2\2\7[\3\2\2\2\t]\3\2\2\2\13_\3\2"+ - "\2\2\rd\3\2\2\2\17j\3\2\2\2\21m\3\2\2\2\23r\3\2\2\2\25w\3\2\2\2\27z\3"+ - "\2\2\2\31\u0080\3\2\2\2\33\u0083\3\2\2\2\35\u0086\3\2\2\2\37\u0088\3\2"+ - "\2\2!\u008a\3\2\2\2#\u008c\3\2\2\2%\u008e\3\2\2\2\'\u0090\3\2\2\2)\u0092"+ - "\3\2\2\2+\u0095\3\2\2\2-\u0098\3\2\2\2/\u009b\3\2\2\2\61\u009e\3\2\2\2"+ - "\63\u00a0\3\2\2\2\65\u00a2\3\2\2\2\67\u00a5\3\2\2\29\u00a8\3\2\2\2;\u00ac"+ - "\3\2\2\2=\u00b0\3\2\2\2?\u00b5\3\2\2\2A\u00ba\3\2\2\2C\u00bd\3\2\2\2E"+ - "\u00bf\3\2\2\2G\u00c1\3\2\2\2I\u00c5\3\2\2\2K\u00ca\3\2\2\2M\u00d0\3\2"+ - "\2\2O\u00df\3\2\2\2Q\u00e1\3\2\2\2S\u00e5\3\2\2\2U\u00f0\3\2\2\2WX\7*"+ - "\2\2X\4\3\2\2\2YZ\7+\2\2Z\6\3\2\2\2[\\\7}\2\2\\\b\3\2\2\2]^\7\177\2\2"+ - "^\n\3\2\2\2_`\7t\2\2`a\7g\2\2ab\7c\2\2bc\7f\2\2c\f\3\2\2\2de\7r\2\2ef"+ - "\7t\2\2fg\7k\2\2gh\7p\2\2hi\7v\2\2i\16\3\2\2\2jk\7k\2\2kl\7h\2\2l\20\3"+ - "\2\2\2mn\7v\2\2no\7j\2\2op\7g\2\2pq\7p\2\2q\22\3\2\2\2rs\7g\2\2st\7n\2"+ - "\2tu\7u\2\2uv\7g\2\2v\24\3\2\2\2wx\7h\2\2xy\7k\2\2y\26\3\2\2\2z{\7y\2"+ - "\2{|\7j\2\2|}\7k\2\2}~\7n\2\2~\177\7g\2\2\177\30\3\2\2\2\u0080\u0081\7"+ - "f\2\2\u0081\u0082\7q\2\2\u0082\32\3\2\2\2\u0083\u0084\7q\2\2\u0084\u0085"+ - "\7f\2\2\u0085\34\3\2\2\2\u0086\u0087\7-\2\2\u0087\36\3\2\2\2\u0088\u0089"+ - "\7/\2\2\u0089 \3\2\2\2\u008a\u008b\7#\2\2\u008b\"\3\2\2\2\u008c\u008d"+ - "\7,\2\2\u008d$\3\2\2\2\u008e\u008f\7\61\2\2\u008f&\3\2\2\2\u0090\u0091"+ - "\7\'\2\2\u0091(\3\2\2\2\u0092\u0093\7>\2\2\u0093\u0094\7?\2\2\u0094*\3"+ - "\2\2\2\u0095\u0096\7@\2\2\u0096\u0097\7?\2\2\u0097,\3\2\2\2\u0098\u0099"+ - "\7>\2\2\u0099\u009a\7@\2\2\u009a.\3\2\2\2\u009b\u009c\7?\2\2\u009c\u009d"+ - "\7?\2\2\u009d\60\3\2\2\2\u009e\u009f\7>\2\2\u009f\62\3\2\2\2\u00a0\u00a1"+ - "\7@\2\2\u00a1\64\3\2\2\2\u00a2\u00a3\7(\2\2\u00a3\u00a4\7(\2\2\u00a4\66"+ - "\3\2\2\2\u00a5\u00a6\7~\2\2\u00a6\u00a7\7~\2\2\u00a78\3\2\2\2\u00a8\u00a9"+ - "\7x\2\2\u00a9\u00aa\7c\2\2\u00aa\u00ab\7t\2\2\u00ab:\3\2\2\2\u00ac\u00ad"+ - "\7k\2\2\u00ad\u00ae\7p\2\2\u00ae\u00af\7v\2\2\u00af<\3\2\2\2\u00b0\u00b1"+ - "\7d\2\2\u00b1\u00b2\7q\2\2\u00b2\u00b3\7q\2\2\u00b3\u00b4\7n\2\2\u00b4"+ - ">\3\2\2\2\u00b5\u00b6\7e\2\2\u00b6\u00b7\7j\2\2\u00b7\u00b8\7c\2\2\u00b8"+ - "\u00b9\7t\2\2\u00b9@\3\2\2\2\u00ba\u00bb\7<\2\2\u00bb\u00bc\7?\2\2\u00bc"+ - "B\3\2\2\2\u00bd\u00be\7=\2\2\u00beD\3\2\2\2\u00bf\u00c0\7.\2\2\u00c0F"+ - "\3\2\2\2\u00c1\u00c2\7)\2\2\u00c2\u00c3\13\2\2\2\u00c3\u00c4\7)\2\2\u00c4"+ - "H\3\2\2\2\u00c5\u00c6\7v\2\2\u00c6\u00c7\7t\2\2\u00c7\u00c8\7w\2\2\u00c8"+ - "\u00c9\7g\2\2\u00c9J\3\2\2\2\u00ca\u00cb\7h\2\2\u00cb\u00cc\7c\2\2\u00cc"+ - "\u00cd\7n\2\2\u00cd\u00ce\7u\2\2\u00ce\u00cf\7g\2\2\u00cfL\3\2\2\2\u00d0"+ - "\u00d4\t\2\2\2\u00d1\u00d3\t\3\2\2\u00d2\u00d1\3\2\2\2\u00d3\u00d6\3\2"+ - "\2\2\u00d4\u00d2\3\2\2\2\u00d4\u00d5\3\2\2\2\u00d5N\3\2\2\2\u00d6\u00d4"+ - "\3\2\2\2\u00d7\u00e0\7\62\2\2\u00d8\u00dc\t\4\2\2\u00d9\u00db\t\5\2\2"+ - "\u00da\u00d9\3\2\2\2\u00db\u00de\3\2\2\2\u00dc\u00da\3\2\2\2\u00dc\u00dd"+ - "\3\2\2\2\u00dd\u00e0\3\2\2\2\u00de\u00dc\3\2\2\2\u00df\u00d7\3\2\2\2\u00df"+ - "\u00d8\3\2\2\2\u00e0P\3\2\2\2\u00e1\u00e2\t\6\2\2\u00e2\u00e3\3\2\2\2"+ - "\u00e3\u00e4\b)\2\2\u00e4R\3\2\2\2\u00e5\u00e6\7\61\2\2\u00e6\u00e7\7"+ - "\61\2\2\u00e7\u00eb\3\2\2\2\u00e8\u00ea\n\7\2\2\u00e9\u00e8\3\2\2\2\u00ea"+ - "\u00ed\3\2\2\2\u00eb\u00e9\3\2\2\2\u00eb\u00ec\3\2\2\2\u00ec\u00ee\3\2"+ - "\2\2\u00ed\u00eb\3\2\2\2\u00ee\u00ef\b*\2\2\u00efT\3\2\2\2\u00f0\u00f1"+ - "\7\61\2\2\u00f1\u00f2\7,\2\2\u00f2\u00f6\3\2\2\2\u00f3\u00f5\13\2\2\2"+ - "\u00f4\u00f3\3\2\2\2\u00f5\u00f8\3\2\2\2\u00f6\u00f7\3\2\2\2\u00f6\u00f4"+ - "\3\2\2\2\u00f7\u00f9\3\2\2\2\u00f8\u00f6\3\2\2\2\u00f9\u00fa\7,\2\2\u00fa"+ - "\u00fb\7\61\2\2\u00fb\u00fc\3\2\2\2\u00fc\u00fd\b+\2\2\u00fdV\3\2\2\2"+ - "\b\2\u00d4\u00dc\u00df\u00eb\u00f6\3\b\2\2"; + "\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4"+ + ",\t,\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\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\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\n\3\13\3"+ + "\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\16\3\16\3\16\3\17\3\17"+ + "\3\20\3\20\3\21\3\21\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\25\3\26"+ + "\3\26\3\26\3\27\3\27\3\27\3\30\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33"+ + "\3\33\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\36"+ + "\3\36\3\36\3\36\3\37\3\37\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\'\3\'\3"+ + "\'\3(\3(\7(\u00de\n(\f(\16(\u00e1\13(\3)\3)\3)\7)\u00e6\n)\f)\16)\u00e9"+ + "\13)\5)\u00eb\n)\3*\3*\3*\3*\3+\3+\3+\3+\7+\u00f5\n+\f+\16+\u00f8\13+"+ + "\3+\3+\3,\3,\3,\3,\7,\u0100\n,\f,\16,\u0103\13,\3,\3,\3,\3,\3,\3\u0101"+ + "\2-\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*S+U,W-\3\2\b\5\2C\\aac|\6\2\62;C\\aac|\3\2"+ + "\63;\3\2\62;\5\2\13\f\17\17\"\"\4\2\f\f\17\17\2\u010d\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\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2"+ + "\2\2\3Y\3\2\2\2\5[\3\2\2\2\7]\3\2\2\2\t_\3\2\2\2\13a\3\2\2\2\rf\3\2\2"+ + "\2\17l\3\2\2\2\21o\3\2\2\2\23t\3\2\2\2\25y\3\2\2\2\27|\3\2\2\2\31\u0082"+ + "\3\2\2\2\33\u0085\3\2\2\2\35\u0088\3\2\2\2\37\u008a\3\2\2\2!\u008c\3\2"+ + "\2\2#\u008e\3\2\2\2%\u0090\3\2\2\2\'\u0092\3\2\2\2)\u0094\3\2\2\2+\u0097"+ + "\3\2\2\2-\u009a\3\2\2\2/\u009d\3\2\2\2\61\u00a0\3\2\2\2\63\u00a2\3\2\2"+ + "\2\65\u00a4\3\2\2\2\67\u00a7\3\2\2\29\u00aa\3\2\2\2;\u00ae\3\2\2\2=\u00b7"+ + "\3\2\2\2?\u00bb\3\2\2\2A\u00c0\3\2\2\2C\u00c5\3\2\2\2E\u00c8\3\2\2\2G"+ + "\u00ca\3\2\2\2I\u00cc\3\2\2\2K\u00d0\3\2\2\2M\u00d5\3\2\2\2O\u00db\3\2"+ + "\2\2Q\u00ea\3\2\2\2S\u00ec\3\2\2\2U\u00f0\3\2\2\2W\u00fb\3\2\2\2YZ\7*"+ + "\2\2Z\4\3\2\2\2[\\\7+\2\2\\\6\3\2\2\2]^\7}\2\2^\b\3\2\2\2_`\7\177\2\2"+ + "`\n\3\2\2\2ab\7t\2\2bc\7g\2\2cd\7c\2\2de\7f\2\2e\f\3\2\2\2fg\7r\2\2gh"+ + "\7t\2\2hi\7k\2\2ij\7p\2\2jk\7v\2\2k\16\3\2\2\2lm\7k\2\2mn\7h\2\2n\20\3"+ + "\2\2\2op\7v\2\2pq\7j\2\2qr\7g\2\2rs\7p\2\2s\22\3\2\2\2tu\7g\2\2uv\7n\2"+ + "\2vw\7u\2\2wx\7g\2\2x\24\3\2\2\2yz\7h\2\2z{\7k\2\2{\26\3\2\2\2|}\7y\2"+ + "\2}~\7j\2\2~\177\7k\2\2\177\u0080\7n\2\2\u0080\u0081\7g\2\2\u0081\30\3"+ + "\2\2\2\u0082\u0083\7f\2\2\u0083\u0084\7q\2\2\u0084\32\3\2\2\2\u0085\u0086"+ + "\7q\2\2\u0086\u0087\7f\2\2\u0087\34\3\2\2\2\u0088\u0089\7-\2\2\u0089\36"+ + "\3\2\2\2\u008a\u008b\7/\2\2\u008b \3\2\2\2\u008c\u008d\7#\2\2\u008d\""+ + "\3\2\2\2\u008e\u008f\7,\2\2\u008f$\3\2\2\2\u0090\u0091\7\61\2\2\u0091"+ + "&\3\2\2\2\u0092\u0093\7\'\2\2\u0093(\3\2\2\2\u0094\u0095\7>\2\2\u0095"+ + "\u0096\7?\2\2\u0096*\3\2\2\2\u0097\u0098\7@\2\2\u0098\u0099\7?\2\2\u0099"+ + ",\3\2\2\2\u009a\u009b\7>\2\2\u009b\u009c\7@\2\2\u009c.\3\2\2\2\u009d\u009e"+ + "\7?\2\2\u009e\u009f\7?\2\2\u009f\60\3\2\2\2\u00a0\u00a1\7>\2\2\u00a1\62"+ + "\3\2\2\2\u00a2\u00a3\7@\2\2\u00a3\64\3\2\2\2\u00a4\u00a5\7(\2\2\u00a5"+ + "\u00a6\7(\2\2\u00a6\66\3\2\2\2\u00a7\u00a8\7~\2\2\u00a8\u00a9\7~\2\2\u00a9"+ + "8\3\2\2\2\u00aa\u00ab\7x\2\2\u00ab\u00ac\7c\2\2\u00ac\u00ad\7t\2\2\u00ad"+ + ":\3\2\2\2\u00ae\u00af\7h\2\2\u00af\u00b0\7w\2\2\u00b0\u00b1\7p\2\2\u00b1"+ + "\u00b2\7e\2\2\u00b2\u00b3\7v\2\2\u00b3\u00b4\7k\2\2\u00b4\u00b5\7q\2\2"+ + "\u00b5\u00b6\7p\2\2\u00b6<\3\2\2\2\u00b7\u00b8\7k\2\2\u00b8\u00b9\7p\2"+ + "\2\u00b9\u00ba\7v\2\2\u00ba>\3\2\2\2\u00bb\u00bc\7d\2\2\u00bc\u00bd\7"+ + "q\2\2\u00bd\u00be\7q\2\2\u00be\u00bf\7n\2\2\u00bf@\3\2\2\2\u00c0\u00c1"+ + "\7e\2\2\u00c1\u00c2\7j\2\2\u00c2\u00c3\7c\2\2\u00c3\u00c4\7t\2\2\u00c4"+ + "B\3\2\2\2\u00c5\u00c6\7<\2\2\u00c6\u00c7\7?\2\2\u00c7D\3\2\2\2\u00c8\u00c9"+ + "\7=\2\2\u00c9F\3\2\2\2\u00ca\u00cb\7.\2\2\u00cbH\3\2\2\2\u00cc\u00cd\7"+ + ")\2\2\u00cd\u00ce\13\2\2\2\u00ce\u00cf\7)\2\2\u00cfJ\3\2\2\2\u00d0\u00d1"+ + "\7v\2\2\u00d1\u00d2\7t\2\2\u00d2\u00d3\7w\2\2\u00d3\u00d4\7g\2\2\u00d4"+ + "L\3\2\2\2\u00d5\u00d6\7h\2\2\u00d6\u00d7\7c\2\2\u00d7\u00d8\7n\2\2\u00d8"+ + "\u00d9\7u\2\2\u00d9\u00da\7g\2\2\u00daN\3\2\2\2\u00db\u00df\t\2\2\2\u00dc"+ + "\u00de\t\3\2\2\u00dd\u00dc\3\2\2\2\u00de\u00e1\3\2\2\2\u00df\u00dd\3\2"+ + "\2\2\u00df\u00e0\3\2\2\2\u00e0P\3\2\2\2\u00e1\u00df\3\2\2\2\u00e2\u00eb"+ + "\7\62\2\2\u00e3\u00e7\t\4\2\2\u00e4\u00e6\t\5\2\2\u00e5\u00e4\3\2\2\2"+ + "\u00e6\u00e9\3\2\2\2\u00e7\u00e5\3\2\2\2\u00e7\u00e8\3\2\2\2\u00e8\u00eb"+ + "\3\2\2\2\u00e9\u00e7\3\2\2\2\u00ea\u00e2\3\2\2\2\u00ea\u00e3\3\2\2\2\u00eb"+ + "R\3\2\2\2\u00ec\u00ed\t\6\2\2\u00ed\u00ee\3\2\2\2\u00ee\u00ef\b*\2\2\u00ef"+ + "T\3\2\2\2\u00f0\u00f1\7\61\2\2\u00f1\u00f2\7\61\2\2\u00f2\u00f6\3\2\2"+ + "\2\u00f3\u00f5\n\7\2\2\u00f4\u00f3\3\2\2\2\u00f5\u00f8\3\2\2\2\u00f6\u00f4"+ + "\3\2\2\2\u00f6\u00f7\3\2\2\2\u00f7\u00f9\3\2\2\2\u00f8\u00f6\3\2\2\2\u00f9"+ + "\u00fa\b+\2\2\u00faV\3\2\2\2\u00fb\u00fc\7\61\2\2\u00fc\u00fd\7,\2\2\u00fd"+ + "\u0101\3\2\2\2\u00fe\u0100\13\2\2\2\u00ff\u00fe\3\2\2\2\u0100\u0103\3"+ + "\2\2\2\u0101\u0102\3\2\2\2\u0101\u00ff\3\2\2\2\u0102\u0104\3\2\2\2\u0103"+ + "\u0101\3\2\2\2\u0104\u0105\7,\2\2\u0105\u0106\7\61\2\2\u0106\u0107\3\2"+ + "\2\2\u0107\u0108\b,\2\2\u0108X\3\2\2\2\b\2\u00df\u00e7\u00ea\u00f6\u0101"+ + "\3\b\2\2"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/pp/s1184725/boppi/BasicLexer.tokens b/src/pp/s1184725/boppi/BasicLexer.tokens index 5686c68..a139178 100644 --- a/src/pp/s1184725/boppi/BasicLexer.tokens +++ b/src/pp/s1184725/boppi/BasicLexer.tokens @@ -26,20 +26,21 @@ GT=25 AND=26 OR=27 DECLARE=28 -INTTYPE=29 -BOOLTYPE=30 -CHARTYPE=31 -ASSIGN=32 -COMPOUND=33 -LISTDELIM=34 -CHAR=35 -TRUE=36 -FALSE=37 -IDENTIFIER=38 -LITERAL10=39 -WHITESPACE=40 -LINECOMMENT=41 -BLOCKCOMMENT=42 +FUNCTION=29 +INTTYPE=30 +BOOLTYPE=31 +CHARTYPE=32 +ASSIGN=33 +COMPOUND=34 +LISTDELIM=35 +CHAR=36 +TRUE=37 +FALSE=38 +IDENTIFIER=39 +LITERAL10=40 +WHITESPACE=41 +LINECOMMENT=42 +BLOCKCOMMENT=43 '('=1 ')'=2 '{'=3 @@ -68,11 +69,12 @@ BLOCKCOMMENT=42 '&&'=26 '||'=27 'var'=28 -'int'=29 -'bool'=30 -'char'=31 -':='=32 -';'=33 -','=34 -'true'=36 -'false'=37 +'function'=29 +'int'=30 +'bool'=31 +'char'=32 +':='=33 +';'=34 +','=35 +'true'=37 +'false'=38 diff --git a/src/pp/s1184725/boppi/BasicParser.java b/src/pp/s1184725/boppi/BasicParser.java index bee716c..06b13ef 100644 --- a/src/pp/s1184725/boppi/BasicParser.java +++ b/src/pp/s1184725/boppi/BasicParser.java @@ -20,9 +20,10 @@ public class BasicParser extends Parser { PAROPEN=1, PARCLOSE=2, BRAOPEN=3, BRACLOSE=4, IN=5, OUT=6, IFOPEN=7, IFTRUE=8, IFFALSE=9, IFCLOSE=10, WHILEOPEN=11, WHILETRUE=12, WHILECLOSE=13, PLUS=14, MINUS=15, NOT=16, MULTIPLY=17, DIVIDE=18, MODULO=19, LEQ=20, GTE=21, NEQ=22, - EQ=23, LT=24, GT=25, AND=26, OR=27, DECLARE=28, INTTYPE=29, BOOLTYPE=30, - CHARTYPE=31, ASSIGN=32, COMPOUND=33, LISTDELIM=34, CHAR=35, TRUE=36, FALSE=37, - IDENTIFIER=38, LITERAL10=39, WHITESPACE=40, LINECOMMENT=41, BLOCKCOMMENT=42; + EQ=23, LT=24, GT=25, AND=26, OR=27, DECLARE=28, FUNCTION=29, INTTYPE=30, + BOOLTYPE=31, CHARTYPE=32, ASSIGN=33, COMPOUND=34, LISTDELIM=35, CHAR=36, + TRUE=37, FALSE=38, IDENTIFIER=39, LITERAL10=40, WHITESPACE=41, LINECOMMENT=42, + BLOCKCOMMENT=43; public static final int RULE_program = 0, RULE_expr = 1, RULE_singleExpr = 2, RULE_type = 3, RULE_variable = 4; public static final String[] ruleNames = { @@ -33,16 +34,16 @@ public class BasicParser extends Parser { null, "'('", "')'", "'{'", "'}'", "'read'", "'print'", "'if'", "'then'", "'else'", "'fi'", "'while'", "'do'", "'od'", "'+'", "'-'", "'!'", "'*'", "'/'", "'%'", "'<='", "'>='", "'<>'", "'=='", "'<'", "'>'", "'&&'", "'||'", - "'var'", "'int'", "'bool'", "'char'", "':='", "';'", "','", null, "'true'", - "'false'" + "'var'", "'function'", "'int'", "'bool'", "'char'", "':='", "';'", "','", + null, "'true'", "'false'" }; private static final String[] _SYMBOLIC_NAMES = { null, "PAROPEN", "PARCLOSE", "BRAOPEN", "BRACLOSE", "IN", "OUT", "IFOPEN", "IFTRUE", "IFFALSE", "IFCLOSE", "WHILEOPEN", "WHILETRUE", "WHILECLOSE", "PLUS", "MINUS", "NOT", "MULTIPLY", "DIVIDE", "MODULO", "LEQ", "GTE", - "NEQ", "EQ", "LT", "GT", "AND", "OR", "DECLARE", "INTTYPE", "BOOLTYPE", - "CHARTYPE", "ASSIGN", "COMPOUND", "LISTDELIM", "CHAR", "TRUE", "FALSE", - "IDENTIFIER", "LITERAL10", "WHITESPACE", "LINECOMMENT", "BLOCKCOMMENT" + "NEQ", "EQ", "LT", "GT", "AND", "OR", "DECLARE", "FUNCTION", "INTTYPE", + "BOOLTYPE", "CHARTYPE", "ASSIGN", "COMPOUND", "LISTDELIM", "CHAR", "TRUE", + "FALSE", "IDENTIFIER", "LITERAL10", "WHITESPACE", "LINECOMMENT", "BLOCKCOMMENT" }; public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); @@ -174,7 +175,7 @@ public class BasicParser extends Parser { setState(16); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << PAROPEN) | (1L << BRAOPEN) | (1L << IN) | (1L << OUT) | (1L << IFOPEN) | (1L << WHILEOPEN) | (1L << PLUS) | (1L << MINUS) | (1L << NOT) | (1L << DECLARE) | (1L << CHAR) | (1L << TRUE) | (1L << FALSE) | (1L << IDENTIFIER) | (1L << LITERAL10))) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << PAROPEN) | (1L << BRAOPEN) | (1L << IN) | (1L << OUT) | (1L << IFOPEN) | (1L << WHILEOPEN) | (1L << PLUS) | (1L << MINUS) | (1L << NOT) | (1L << DECLARE) | (1L << FUNCTION) | (1L << CHAR) | (1L << TRUE) | (1L << FALSE) | (1L << IDENTIFIER) | (1L << LITERAL10))) != 0)) { { setState(15); singleExpr(0); @@ -394,6 +395,29 @@ public class BasicParser extends Parser { else return visitor.visitChildren(this); } } + public static class CallContext extends SingleExprContext { + public VariableContext variable() { + return getRuleContext(VariableContext.class,0); + } + public TerminalNode PAROPEN() { return getToken(BasicParser.PAROPEN, 0); } + public List expr() { + return getRuleContexts(ExprContext.class); + } + public ExprContext expr(int i) { + return getRuleContext(ExprContext.class,i); + } + public TerminalNode PARCLOSE() { return getToken(BasicParser.PARCLOSE, 0); } + public List LISTDELIM() { return getTokens(BasicParser.LISTDELIM); } + public TerminalNode LISTDELIM(int i) { + return getToken(BasicParser.LISTDELIM, i); + } + public CallContext(SingleExprContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof BasicVisitor ) return ((BasicVisitor)visitor).visitCall(this); + else return visitor.visitChildren(this); + } + } public static class NumberContext extends SingleExprContext { public TerminalNode LITERAL10() { return getToken(BasicParser.LITERAL10, 0); } public NumberContext(SingleExprContext ctx) { copyFrom(ctx); } @@ -403,6 +427,37 @@ public class BasicParser extends Parser { else return visitor.visitChildren(this); } } + public static class FuncDeclareContext extends SingleExprContext { + public TypeContext result; + public Token name; + public SingleExprContext body; + public TerminalNode FUNCTION() { return getToken(BasicParser.FUNCTION, 0); } + public TerminalNode PAROPEN() { return getToken(BasicParser.PAROPEN, 0); } + public List type() { + return getRuleContexts(TypeContext.class); + } + public TypeContext type(int i) { + return getRuleContext(TypeContext.class,i); + } + public List IDENTIFIER() { return getTokens(BasicParser.IDENTIFIER); } + public TerminalNode IDENTIFIER(int i) { + return getToken(BasicParser.IDENTIFIER, i); + } + public TerminalNode PARCLOSE() { return getToken(BasicParser.PARCLOSE, 0); } + public SingleExprContext singleExpr() { + return getRuleContext(SingleExprContext.class,0); + } + public List LISTDELIM() { return getTokens(BasicParser.LISTDELIM); } + public TerminalNode LISTDELIM(int i) { + return getToken(BasicParser.LISTDELIM, i); + } + public FuncDeclareContext(SingleExprContext ctx) { copyFrom(ctx); } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof BasicVisitor ) return ((BasicVisitor)visitor).visitFuncDeclare(this); + else return visitor.visitChildren(this); + } + } public static class CharContext extends SingleExprContext { public TerminalNode CHAR() { return getToken(BasicParser.CHAR, 0); } public CharContext(SingleExprContext ctx) { copyFrom(ctx); } @@ -514,9 +569,9 @@ public class BasicParser extends Parser { int _alt; enterOuterAlt(_localctx, 1); { - setState(86); + setState(116); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,5,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) { case 1: { _localctx = new ParensContext(_localctx); @@ -608,56 +663,87 @@ public class BasicParser extends Parser { break; case 5: { - _localctx = new IfContext(_localctx); + _localctx = new CallContext(_localctx); _ctx = _localctx; _prevctx = _localctx; setState(56); - match(IFOPEN); + variable(); setState(57); - ((IfContext)_localctx).cond = expr(); + match(PAROPEN); setState(58); - match(IFTRUE); - setState(59); - ((IfContext)_localctx).onTrue = expr(); - setState(62); + expr(); + setState(63); _errHandler.sync(this); _la = _input.LA(1); - if (_la==IFFALSE) { + while (_la==LISTDELIM) { { + { + setState(59); + match(LISTDELIM); setState(60); - match(IFFALSE); - setState(61); - ((IfContext)_localctx).onFalse = expr(); + expr(); } + } + setState(65); + _errHandler.sync(this); + _la = _input.LA(1); } - - setState(64); - match(IFCLOSE); + setState(66); + match(PARCLOSE); } break; case 6: { - _localctx = new WhileContext(_localctx); + _localctx = new IfContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(66); - match(WHILEOPEN); - setState(67); - ((WhileContext)_localctx).cond = expr(); setState(68); - match(WHILETRUE); + match(IFOPEN); setState(69); - ((WhileContext)_localctx).onTrue = expr(); + ((IfContext)_localctx).cond = expr(); setState(70); - match(WHILECLOSE); + match(IFTRUE); + setState(71); + ((IfContext)_localctx).onTrue = expr(); + setState(74); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==IFFALSE) { + { + setState(72); + match(IFFALSE); + setState(73); + ((IfContext)_localctx).onFalse = expr(); + } + } + + setState(76); + match(IFCLOSE); } break; case 7: + { + _localctx = new WhileContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(78); + match(WHILEOPEN); + setState(79); + ((WhileContext)_localctx).cond = expr(); + setState(80); + match(WHILETRUE); + setState(81); + ((WhileContext)_localctx).onTrue = expr(); + setState(82); + match(WHILECLOSE); + } + break; + case 8: { _localctx = new Prefix1Context(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(72); + setState(84); ((Prefix1Context)_localctx).op = _input.LT(1); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << PLUS) | (1L << MINUS) | (1L << NOT))) != 0)) ) { @@ -668,69 +754,110 @@ public class BasicParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(73); - singleExpr(12); - } - break; - case 8: - { - _localctx = new DeclareContext(_localctx); - _ctx = _localctx; - _prevctx = _localctx; - setState(74); - match(DECLARE); - setState(75); - type(); - setState(76); - match(IDENTIFIER); + setState(85); + singleExpr(13); } break; case 9: { - _localctx = new AssignContext(_localctx); + _localctx = new DeclareContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(78); - variable(); - setState(79); - match(ASSIGN); - setState(80); - singleExpr(5); + setState(86); + match(DECLARE); + setState(87); + type(); + setState(88); + match(IDENTIFIER); } break; case 10: { - _localctx = new VarContext(_localctx); + _localctx = new FuncDeclareContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(82); - variable(); + setState(90); + match(FUNCTION); + setState(91); + ((FuncDeclareContext)_localctx).result = type(); + setState(92); + ((FuncDeclareContext)_localctx).name = match(IDENTIFIER); + setState(93); + match(PAROPEN); + setState(94); + type(); + setState(95); + match(IDENTIFIER); + setState(102); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==LISTDELIM) { + { + { + setState(96); + match(LISTDELIM); + setState(97); + type(); + setState(98); + match(IDENTIFIER); + } + } + setState(104); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(105); + match(PARCLOSE); + setState(106); + ((FuncDeclareContext)_localctx).body = singleExpr(6); } break; case 11: { - _localctx = new NumberContext(_localctx); + _localctx = new AssignContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(83); - match(LITERAL10); + setState(108); + variable(); + setState(109); + match(ASSIGN); + setState(110); + singleExpr(5); } break; case 12: { - _localctx = new CharContext(_localctx); + _localctx = new VarContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(84); - match(CHAR); + setState(112); + variable(); } break; case 13: + { + _localctx = new NumberContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(113); + match(LITERAL10); + } + break; + case 14: + { + _localctx = new CharContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(114); + match(CHAR); + } + break; + case 15: { _localctx = new BoolContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(85); + setState(115); _la = _input.LA(1); if ( !(_la==TRUE || _la==FALSE) ) { _errHandler.recoverInline(this); @@ -744,25 +871,25 @@ public class BasicParser extends Parser { break; } _ctx.stop = _input.LT(-1); - setState(105); + setState(135); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,7,_ctx); + _alt = getInterpreter().adaptivePredict(_input,9,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(103); + setState(133); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,8,_ctx) ) { case 1: { _localctx = new Infix1Context(new SingleExprContext(_parentctx, _parentState)); ((Infix1Context)_localctx).lhs = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_singleExpr); - setState(88); - if (!(precpred(_ctx, 11))) throw new FailedPredicateException(this, "precpred(_ctx, 11)"); - setState(89); + setState(118); + if (!(precpred(_ctx, 12))) throw new FailedPredicateException(this, "precpred(_ctx, 12)"); + setState(119); ((Infix1Context)_localctx).op = _input.LT(1); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << MULTIPLY) | (1L << DIVIDE) | (1L << MODULO))) != 0)) ) { @@ -773,8 +900,8 @@ public class BasicParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(90); - ((Infix1Context)_localctx).rhs = singleExpr(12); + setState(120); + ((Infix1Context)_localctx).rhs = singleExpr(13); } break; case 2: @@ -782,9 +909,9 @@ public class BasicParser extends Parser { _localctx = new Infix2Context(new SingleExprContext(_parentctx, _parentState)); ((Infix2Context)_localctx).lhs = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_singleExpr); - setState(91); - if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)"); - setState(92); + setState(121); + if (!(precpred(_ctx, 11))) throw new FailedPredicateException(this, "precpred(_ctx, 11)"); + setState(122); ((Infix2Context)_localctx).op = _input.LT(1); _la = _input.LA(1); if ( !(_la==PLUS || _la==MINUS) ) { @@ -795,8 +922,8 @@ public class BasicParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(93); - ((Infix2Context)_localctx).rhs = singleExpr(11); + setState(123); + ((Infix2Context)_localctx).rhs = singleExpr(12); } break; case 3: @@ -804,9 +931,9 @@ public class BasicParser extends Parser { _localctx = new Infix3Context(new SingleExprContext(_parentctx, _parentState)); ((Infix3Context)_localctx).lhs = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_singleExpr); - setState(94); - if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); - setState(95); + setState(124); + if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)"); + setState(125); ((Infix3Context)_localctx).op = _input.LT(1); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LEQ) | (1L << GTE) | (1L << NEQ) | (1L << EQ) | (1L << LT) | (1L << GT))) != 0)) ) { @@ -817,8 +944,8 @@ public class BasicParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(96); - ((Infix3Context)_localctx).rhs = singleExpr(10); + setState(126); + ((Infix3Context)_localctx).rhs = singleExpr(11); } break; case 4: @@ -826,12 +953,12 @@ public class BasicParser extends Parser { _localctx = new Infix4Context(new SingleExprContext(_parentctx, _parentState)); ((Infix4Context)_localctx).lhs = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_singleExpr); - setState(97); - if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)"); - setState(98); + setState(127); + if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); + setState(128); match(AND); - setState(99); - ((Infix4Context)_localctx).rhs = singleExpr(9); + setState(129); + ((Infix4Context)_localctx).rhs = singleExpr(10); } break; case 5: @@ -839,20 +966,20 @@ public class BasicParser extends Parser { _localctx = new Infix5Context(new SingleExprContext(_parentctx, _parentState)); ((Infix5Context)_localctx).lhs = _prevctx; pushNewRecursionContext(_localctx, _startState, RULE_singleExpr); - setState(100); - if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)"); - setState(101); + setState(130); + if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)"); + setState(131); match(OR); - setState(102); - ((Infix5Context)_localctx).rhs = singleExpr(8); + setState(132); + ((Infix5Context)_localctx).rhs = singleExpr(9); } break; } } } - setState(107); + setState(137); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,7,_ctx); + _alt = getInterpreter().adaptivePredict(_input,9,_ctx); } } } @@ -891,7 +1018,7 @@ public class BasicParser extends Parser { enterRule(_localctx, 6, RULE_type); int _la; try { - setState(110); + setState(140); _errHandler.sync(this); switch (_input.LA(1)) { case INTTYPE: @@ -899,7 +1026,7 @@ public class BasicParser extends Parser { case CHARTYPE: enterOuterAlt(_localctx, 1); { - setState(108); + setState(138); ((TypeContext)_localctx).staticType = _input.LT(1); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << INTTYPE) | (1L << BOOLTYPE) | (1L << CHARTYPE))) != 0)) ) { @@ -915,7 +1042,7 @@ public class BasicParser extends Parser { case IDENTIFIER: enterOuterAlt(_localctx, 2); { - setState(109); + setState(139); variable(); } break; @@ -953,7 +1080,7 @@ public class BasicParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(112); + setState(142); match(IDENTIFIER); } } @@ -978,51 +1105,61 @@ public class BasicParser extends Parser { private boolean singleExpr_sempred(SingleExprContext _localctx, int predIndex) { switch (predIndex) { case 0: - return precpred(_ctx, 11); + return precpred(_ctx, 12); case 1: - return precpred(_ctx, 10); + return precpred(_ctx, 11); case 2: - return precpred(_ctx, 9); + return precpred(_ctx, 10); case 3: - return precpred(_ctx, 8); + return precpred(_ctx, 9); case 4: - return precpred(_ctx, 7); + return precpred(_ctx, 8); } return true; } public static final String _serializedATN = - "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3,u\4\2\t\2\4\3\t\3"+ - "\4\4\t\4\4\5\t\5\4\6\t\6\3\2\3\2\3\2\3\3\3\3\3\3\5\3\23\n\3\7\3\25\n\3"+ - "\f\3\16\3\30\13\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4"+ - "\3\4\7\4(\n\4\f\4\16\4+\13\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\7\4\64\n\4\f"+ - "\4\16\4\67\13\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4A\n\4\3\4\3\4\3\4\3"+ + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3-\u0093\4\2\t\2\4"+ + "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\3\2\3\2\3\2\3\3\3\3\3\3\5\3\23\n\3\7\3"+ + "\25\n\3\f\3\16\3\30\13\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3"+ + "\4\3\4\3\4\7\4(\n\4\f\4\16\4+\13\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\7\4\64"+ + "\n\4\f\4\16\4\67\13\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\7\4@\n\4\f\4\16\4C\13"+ + "\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4M\n\4\3\4\3\4\3\4\3\4\3\4\3\4\3"+ "\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4"+ - "\3\4\5\4Y\n\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4"+ - "\3\4\7\4j\n\4\f\4\16\4m\13\4\3\5\3\5\5\5q\n\5\3\6\3\6\3\6\2\3\6\7\2\4"+ - "\6\b\n\2\b\3\2\20\22\3\2&\'\3\2\23\25\3\2\20\21\3\2\26\33\3\2\37!\2\u0086"+ - "\2\f\3\2\2\2\4\17\3\2\2\2\6X\3\2\2\2\bp\3\2\2\2\nr\3\2\2\2\f\r\5\4\3\2"+ - "\r\16\7\2\2\3\16\3\3\2\2\2\17\26\5\6\4\2\20\22\7#\2\2\21\23\5\6\4\2\22"+ - "\21\3\2\2\2\22\23\3\2\2\2\23\25\3\2\2\2\24\20\3\2\2\2\25\30\3\2\2\2\26"+ - "\24\3\2\2\2\26\27\3\2\2\2\27\5\3\2\2\2\30\26\3\2\2\2\31\32\b\4\1\2\32"+ - "\33\7\3\2\2\33\34\5\4\3\2\34\35\7\4\2\2\35Y\3\2\2\2\36\37\7\5\2\2\37 "+ - "\5\4\3\2 !\7\6\2\2!Y\3\2\2\2\"#\7\7\2\2#$\7\3\2\2$)\5\n\6\2%&\7$\2\2&"+ - "(\5\n\6\2\'%\3\2\2\2(+\3\2\2\2)\'\3\2\2\2)*\3\2\2\2*,\3\2\2\2+)\3\2\2"+ - "\2,-\7\4\2\2-Y\3\2\2\2./\7\b\2\2/\60\7\3\2\2\60\65\5\4\3\2\61\62\7$\2"+ - "\2\62\64\5\4\3\2\63\61\3\2\2\2\64\67\3\2\2\2\65\63\3\2\2\2\65\66\3\2\2"+ - "\2\668\3\2\2\2\67\65\3\2\2\289\7\4\2\29Y\3\2\2\2:;\7\t\2\2;<\5\4\3\2<"+ - "=\7\n\2\2=@\5\4\3\2>?\7\13\2\2?A\5\4\3\2@>\3\2\2\2@A\3\2\2\2AB\3\2\2\2"+ - "BC\7\f\2\2CY\3\2\2\2DE\7\r\2\2EF\5\4\3\2FG\7\16\2\2GH\5\4\3\2HI\7\17\2"+ - "\2IY\3\2\2\2JK\t\2\2\2KY\5\6\4\16LM\7\36\2\2MN\5\b\5\2NO\7(\2\2OY\3\2"+ - "\2\2PQ\5\n\6\2QR\7\"\2\2RS\5\6\4\7SY\3\2\2\2TY\5\n\6\2UY\7)\2\2VY\7%\2"+ - "\2WY\t\3\2\2X\31\3\2\2\2X\36\3\2\2\2X\"\3\2\2\2X.\3\2\2\2X:\3\2\2\2XD"+ - "\3\2\2\2XJ\3\2\2\2XL\3\2\2\2XP\3\2\2\2XT\3\2\2\2XU\3\2\2\2XV\3\2\2\2X"+ - "W\3\2\2\2Yk\3\2\2\2Z[\f\r\2\2[\\\t\4\2\2\\j\5\6\4\16]^\f\f\2\2^_\t\5\2"+ - "\2_j\5\6\4\r`a\f\13\2\2ab\t\6\2\2bj\5\6\4\fcd\f\n\2\2de\7\34\2\2ej\5\6"+ - "\4\13fg\f\t\2\2gh\7\35\2\2hj\5\6\4\niZ\3\2\2\2i]\3\2\2\2i`\3\2\2\2ic\3"+ - "\2\2\2if\3\2\2\2jm\3\2\2\2ki\3\2\2\2kl\3\2\2\2l\7\3\2\2\2mk\3\2\2\2nq"+ - "\t\7\2\2oq\5\n\6\2pn\3\2\2\2po\3\2\2\2q\t\3\2\2\2rs\7(\2\2s\13\3\2\2\2"+ - "\13\22\26)\65@Xikp"; + "\7\4g\n\4\f\4\16\4j\13\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5"+ + "\4w\n\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\7"+ + "\4\u0088\n\4\f\4\16\4\u008b\13\4\3\5\3\5\5\5\u008f\n\5\3\6\3\6\3\6\2\3"+ + "\6\7\2\4\6\b\n\2\b\3\2\20\22\3\2\'(\3\2\23\25\3\2\20\21\3\2\26\33\3\2"+ + " \"\2\u00a8\2\f\3\2\2\2\4\17\3\2\2\2\6v\3\2\2\2\b\u008e\3\2\2\2\n\u0090"+ + "\3\2\2\2\f\r\5\4\3\2\r\16\7\2\2\3\16\3\3\2\2\2\17\26\5\6\4\2\20\22\7$"+ + "\2\2\21\23\5\6\4\2\22\21\3\2\2\2\22\23\3\2\2\2\23\25\3\2\2\2\24\20\3\2"+ + "\2\2\25\30\3\2\2\2\26\24\3\2\2\2\26\27\3\2\2\2\27\5\3\2\2\2\30\26\3\2"+ + "\2\2\31\32\b\4\1\2\32\33\7\3\2\2\33\34\5\4\3\2\34\35\7\4\2\2\35w\3\2\2"+ + "\2\36\37\7\5\2\2\37 \5\4\3\2 !\7\6\2\2!w\3\2\2\2\"#\7\7\2\2#$\7\3\2\2"+ + "$)\5\n\6\2%&\7%\2\2&(\5\n\6\2\'%\3\2\2\2(+\3\2\2\2)\'\3\2\2\2)*\3\2\2"+ + "\2*,\3\2\2\2+)\3\2\2\2,-\7\4\2\2-w\3\2\2\2./\7\b\2\2/\60\7\3\2\2\60\65"+ + "\5\4\3\2\61\62\7%\2\2\62\64\5\4\3\2\63\61\3\2\2\2\64\67\3\2\2\2\65\63"+ + "\3\2\2\2\65\66\3\2\2\2\668\3\2\2\2\67\65\3\2\2\289\7\4\2\29w\3\2\2\2:"+ + ";\5\n\6\2;<\7\3\2\2\7%\2\2>@\5\4\3\2?=\3\2\2\2@C\3\2\2\2A"+ + "?\3\2\2\2AB\3\2\2\2BD\3\2\2\2CA\3\2\2\2DE\7\4\2\2Ew\3\2\2\2FG\7\t\2\2"+ + "GH\5\4\3\2HI\7\n\2\2IL\5\4\3\2JK\7\13\2\2KM\5\4\3\2LJ\3\2\2\2LM\3\2\2"+ + "\2MN\3\2\2\2NO\7\f\2\2Ow\3\2\2\2PQ\7\r\2\2QR\5\4\3\2RS\7\16\2\2ST\5\4"+ + "\3\2TU\7\17\2\2Uw\3\2\2\2VW\t\2\2\2Ww\5\6\4\17XY\7\36\2\2YZ\5\b\5\2Z["+ + "\7)\2\2[w\3\2\2\2\\]\7\37\2\2]^\5\b\5\2^_\7)\2\2_`\7\3\2\2`a\5\b\5\2a"+ + "h\7)\2\2bc\7%\2\2cd\5\b\5\2de\7)\2\2eg\3\2\2\2fb\3\2\2\2gj\3\2\2\2hf\3"+ + "\2\2\2hi\3\2\2\2ik\3\2\2\2jh\3\2\2\2kl\7\4\2\2lm\5\6\4\bmw\3\2\2\2no\5"+ + "\n\6\2op\7#\2\2pq\5\6\4\7qw\3\2\2\2rw\5\n\6\2sw\7*\2\2tw\7&\2\2uw\t\3"+ + "\2\2v\31\3\2\2\2v\36\3\2\2\2v\"\3\2\2\2v.\3\2\2\2v:\3\2\2\2vF\3\2\2\2"+ + "vP\3\2\2\2vV\3\2\2\2vX\3\2\2\2v\\\3\2\2\2vn\3\2\2\2vr\3\2\2\2vs\3\2\2"+ + "\2vt\3\2\2\2vu\3\2\2\2w\u0089\3\2\2\2xy\f\16\2\2yz\t\4\2\2z\u0088\5\6"+ + "\4\17{|\f\r\2\2|}\t\5\2\2}\u0088\5\6\4\16~\177\f\f\2\2\177\u0080\t\6\2"+ + "\2\u0080\u0088\5\6\4\r\u0081\u0082\f\13\2\2\u0082\u0083\7\34\2\2\u0083"+ + "\u0088\5\6\4\f\u0084\u0085\f\n\2\2\u0085\u0086\7\35\2\2\u0086\u0088\5"+ + "\6\4\13\u0087x\3\2\2\2\u0087{\3\2\2\2\u0087~\3\2\2\2\u0087\u0081\3\2\2"+ + "\2\u0087\u0084\3\2\2\2\u0088\u008b\3\2\2\2\u0089\u0087\3\2\2\2\u0089\u008a"+ + "\3\2\2\2\u008a\7\3\2\2\2\u008b\u0089\3\2\2\2\u008c\u008f\t\7\2\2\u008d"+ + "\u008f\5\n\6\2\u008e\u008c\3\2\2\2\u008e\u008d\3\2\2\2\u008f\t\3\2\2\2"+ + "\u0090\u0091\7)\2\2\u0091\13\3\2\2\2\r\22\26)\65ALhv\u0087\u0089\u008e"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/pp/s1184725/boppi/BasicVisitor.java b/src/pp/s1184725/boppi/BasicVisitor.java index 14f34c5..3863b4b 100644 --- a/src/pp/s1184725/boppi/BasicVisitor.java +++ b/src/pp/s1184725/boppi/BasicVisitor.java @@ -99,6 +99,13 @@ public interface BasicVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitInfix5(BasicParser.Infix5Context ctx); + /** + * Visit a parse tree produced by the {@code call} + * labeled alternative in {@link BasicParser#singleExpr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCall(BasicParser.CallContext ctx); /** * Visit a parse tree produced by the {@code number} * labeled alternative in {@link BasicParser#singleExpr}. @@ -106,6 +113,13 @@ public interface BasicVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitNumber(BasicParser.NumberContext ctx); + /** + * Visit a parse tree produced by the {@code funcDeclare} + * labeled alternative in {@link BasicParser#singleExpr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFuncDeclare(BasicParser.FuncDeclareContext ctx); /** * Visit a parse tree produced by the {@code char} * labeled alternative in {@link BasicParser#singleExpr}. diff --git a/src/pp/s1184725/boppi/BoppiBasicChecker.java b/src/pp/s1184725/boppi/BoppiBasicChecker.java index fcbde00..5bf7110 100644 --- a/src/pp/s1184725/boppi/BoppiBasicChecker.java +++ b/src/pp/s1184725/boppi/BoppiBasicChecker.java @@ -1,7 +1,10 @@ package pp.s1184725.boppi; +import java.util.ArrayList; import java.util.EmptyStackException; +import java.util.List; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; @@ -13,8 +16,8 @@ import pp.s1184725.boppi.BasicParser.*; * tree. * */ -public class BoppiBasicChecker extends BasicBaseVisitor { - private CachingSymbolTable symbols; +public class BoppiBasicChecker extends BasicBaseVisitor { + private CachingSymbolTable symbols; private Annotations an; private Logger log; @@ -34,37 +37,59 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visit(ParseTree tree) { - SimpleType type = super.visit(tree); + public Type visit(ParseTree tree) { + Type type = super.visit(tree); an.types.put(tree, type); + if (an.function.get(tree) == null) + an.function.put(tree, an.currentFunction.peek()); return type; } @Override - public SimpleType visitAssign(AssignContext ctx) { - SimpleType expr = visit(ctx.singleExpr()); - SimpleType var = visit(ctx.variable()); + public Type visitAssign(AssignContext ctx) { + Type expr = visit(ctx.singleExpr()); + Type var = visit(ctx.variable()); checkConstraint(expr, var, ctx); return expr; } @Override - public SimpleType visitBool(BoolContext ctx) { + public Type visitBool(BoolContext ctx) { return SimpleType.BOOL; } @Override - public SimpleType visitBlock(BlockContext ctx) { + public Type visitBlock(BlockContext ctx) { return symbols.withScope(() -> visit(ctx.expr())); } @Override - public SimpleType visitChar(CharContext ctx) { + public Type visitCall(CallContext ctx) { + Type t = visit(ctx.variable()); + + if (t instanceof FunctionType) { + FunctionType type = (FunctionType) t; + if (type.getParameters().size() != ctx.expr().size()) + log.severe(getError(ctx, "Expected %d arguments but got %d.", type.getParameters().size(), + ctx.expr().size())); + + for (int i = 0; i < ctx.expr().size() && i < type.getParameters().size(); i++) + checkConstraint(visit(ctx.expr(i)), type.getParameters().get(i), ctx.expr(i)); + + return type.getReturn(); + } else { + log.severe(getError(ctx, "'%s' is not a function.", ctx.variable().getText())); + return SimpleType.VOID; + } + } + + @Override + public Type visitChar(CharContext ctx) { return SimpleType.CHAR; } @Override - public SimpleType visitExpr(ExprContext ctx) { + public Type visitExpr(ExprContext ctx) { if (ctx.singleExpr(ctx.singleExpr().size() - 1) instanceof DeclareContext) log.severe(getError(ctx, "Compound expression ends with declaration.")); @@ -72,10 +97,13 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitDeclare(DeclareContext ctx) { + public Type visitDeclare(DeclareContext ctx) { try { - Variable var = symbols.put(ctx.IDENTIFIER().getText(), visit(ctx.type())); + Variable var = symbols.put(ctx.IDENTIFIER().getText(), visit(ctx.type())); an.variables.put(ctx, var); + + if (!(var.getType() instanceof SimpleType)) + log.warning("Be careful only to pass pure functions outside their scope."); } catch (EmptyStackException e) { log.severe(getError(ctx, "Declaring variable outside a program.")); } catch (Exception e) { @@ -85,12 +113,40 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitIf(IfContext ctx) { + public Type visitFuncDeclare(FuncDeclareContext ctx) { + try { + List parameterTypes = ctx.type().stream().skip(1).map(this::visit).collect(Collectors.toList()); + FunctionType type = new FunctionType(visit(ctx.result), parameterTypes, symbols.functionDepth); + Variable func = symbols.put(ctx.name.getText(), type); + an.variables.put(ctx, func); + an.currentFunction.push(func); + + type.setLocalDataSize(symbols.withFunctionScope(() -> { + for (int i = 1; i < ctx.type().size(); i++) + try { + Variable var = symbols.put(ctx.IDENTIFIER(i).getText(), an.types.get(ctx.type(i))); + type.getOffsets().add(var.getOffset()); + } catch (Exception e) { + log.severe(getError(ctx, e.getMessage())); + } + checkConstraint(symbols.withScope(() -> visit(ctx.body)), an.types.get(ctx.result), ctx); + })); + } catch (EmptyStackException e) { + log.severe(getError(ctx, "Declaring function outside a program.")); + } catch (Exception e) { + log.severe(getError(ctx, e.getMessage())); + } + an.currentFunction.pop(); + return SimpleType.VOID; + } + + @Override + public Type visitIf(IfContext ctx) { return symbols.withScope(() -> { visit(ctx.cond); if (ctx.onFalse != null) { - SimpleType trueType = symbols.withScope(() -> visit(ctx.onTrue)); - SimpleType falseType = symbols.withScope(() -> visit(ctx.onFalse)); + Type trueType = symbols.withScope(() -> visit(ctx.onTrue)); + Type falseType = symbols.withScope(() -> visit(ctx.onFalse)); return (trueType.equals(falseType)) ? trueType : SimpleType.VOID; } else { @@ -101,7 +157,7 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitInfix1(Infix1Context ctx) { + public Type visitInfix1(Infix1Context ctx) { checkConstraint(visit(ctx.lhs), SimpleType.INT, ctx.lhs); checkConstraint(visit(ctx.rhs), SimpleType.INT, ctx.rhs); @@ -109,7 +165,7 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitInfix2(Infix2Context ctx) { + public Type visitInfix2(Infix2Context ctx) { checkConstraint(visit(ctx.lhs), SimpleType.INT, ctx.lhs); checkConstraint(visit(ctx.rhs), SimpleType.INT, ctx.rhs); @@ -117,9 +173,9 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitInfix3(Infix3Context ctx) { - SimpleType lht = visit(ctx.lhs); - SimpleType rht = visit(ctx.rhs); + public Type visitInfix3(Infix3Context ctx) { + Type lht = visit(ctx.lhs); + Type rht = visit(ctx.rhs); checkConstraint(lht, rht, ctx); switch (ctx.op.getType()) { @@ -134,7 +190,7 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitInfix4(Infix4Context ctx) { + public Type visitInfix4(Infix4Context ctx) { checkConstraint(visit(ctx.lhs), SimpleType.BOOL, ctx.lhs); checkConstraint(visit(ctx.rhs), SimpleType.BOOL, ctx.rhs); @@ -142,7 +198,7 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitInfix5(Infix5Context ctx) { + public Type visitInfix5(Infix5Context ctx) { checkConstraint(visit(ctx.lhs), SimpleType.BOOL, ctx.lhs); checkConstraint(visit(ctx.rhs), SimpleType.BOOL, ctx.rhs); @@ -150,18 +206,18 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitNumber(NumberContext ctx) { + public Type visitNumber(NumberContext ctx) { return SimpleType.INT; } @Override - public SimpleType visitParens(ParensContext ctx) { + public Type visitParens(ParensContext ctx) { return visit(ctx.expr()); } @Override - public SimpleType visitPrefix1(Prefix1Context ctx) { - SimpleType type = visit(ctx.singleExpr()); + public Type visitPrefix1(Prefix1Context ctx) { + Type type = visit(ctx.singleExpr()); switch (ctx.op.getType()) { case BasicLexer.NOT: @@ -178,13 +234,15 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitProgram(ProgramContext ctx) { - symbols.withScope(() -> super.visitProgram(ctx)); + public Type visitProgram(ProgramContext ctx) { + FunctionType main = new FunctionType(SimpleType.VOID, new ArrayList<>(), symbols.functionDepth); + an.currentFunction.push(new Variable(main, 0, 0)); + main.setLocalDataSize(symbols.withFunctionScope(() -> super.visitProgram(ctx))); return null; } @Override - public SimpleType visitRead(ReadContext ctx) { + public Type visitRead(ReadContext ctx) { if (ctx.variable().size() == 1) { return visit(ctx.variable(0)); } else { @@ -194,7 +252,7 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitType(TypeContext ctx) { + public Type visitType(TypeContext ctx) { if (ctx.variable() != null) return visit(ctx.variable()); else @@ -202,27 +260,27 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitVar(VarContext ctx) { + public Type visitVar(VarContext ctx) { return visit(ctx.variable()); } @Override - public SimpleType visitVariable(VariableContext ctx) { + public Type visitVariable(VariableContext ctx) { try { - Variable var = symbols.get(ctx.getText()); + Variable var = symbols.get(ctx.getText()); an.variables.put(ctx, var); return var.getType(); } catch (EmptyStackException e) { log.severe(getError(ctx, "Using variable outside a program.")); } catch (Exception e) { - log.severe(getError(ctx, e.getMessage())); + log.severe(getError(ctx, e.getMessage() != null ? e.getMessage() : "unknown error")); } return SimpleType.VOID; } @Override - public SimpleType visitWhile(WhileContext ctx) { + public Type visitWhile(WhileContext ctx) { return symbols.withScope(() -> { checkConstraint(visit(ctx.cond), SimpleType.BOOL, ctx.cond); symbols.withScope(() -> visit(ctx.onTrue)); @@ -231,9 +289,9 @@ public class BoppiBasicChecker extends BasicBaseVisitor { } @Override - public SimpleType visitWrite(WriteContext ctx) { + public Type visitWrite(WriteContext ctx) { if (ctx.expr().size() == 1) { - SimpleType type = visit(ctx.expr(0)); + Type type = visit(ctx.expr(0)); if (SimpleType.VOID.equals(type)) log.severe(getError(ctx, "Cannot print argument of type %s.", type)); @@ -257,7 +315,7 @@ public class BoppiBasicChecker extends BasicBaseVisitor { * @param node * the context used for logging */ - private void checkConstraint(SimpleType type1, SimpleType type2, ParserRuleContext node) { + private void checkConstraint(Type type1, Type type2, ParserRuleContext node) { if (!type2.equals(type1)) log.severe(getError(node, "Could not match type %s with type %s.", type1.toString(), type2.toString())); } diff --git a/src/pp/s1184725/boppi/BoppiBasicGenerator.java b/src/pp/s1184725/boppi/BoppiBasicGenerator.java index 31c4896..fe53ffb 100644 --- a/src/pp/s1184725/boppi/BoppiBasicGenerator.java +++ b/src/pp/s1184725/boppi/BoppiBasicGenerator.java @@ -2,6 +2,7 @@ package pp.s1184725.boppi; import java.util.*; +import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.tree.*; @@ -9,10 +10,11 @@ import pp.iloc.model.*; import pp.s1184725.boppi.BasicParser.*; public class BoppiBasicGenerator extends BasicBaseVisitor { + private static final int ARBASESIZE = 8; public Program prog; private Annotations an; private int regNum; - private final Reg zero = new Reg("zero"); + private final Reg tempArp = new Reg("ART"), arp = new Reg("ARP"), resultReg = new Reg("RES"); /** * Maps operator tokens to ILOC opcodes. @@ -46,8 +48,6 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { an = annotations; prog = new Program(); regNum = 0; - - emit(OpCode.loadI, new Num(0), zero); } /** @@ -82,12 +82,25 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { return reg; } + private Reg getVar(ParserRuleContext node, Variable var) { + int difference = an.function.get(node).getDepth() + 1 - var.getDepth(); + if (difference > 0) { + emit(node, OpCode.i2i, arp, tempArp); + while (difference-- > 0) + emit(node, OpCode.loadAI, tempArp, new Num(-4), tempArp); + + return tempArp; + } else + return arp; + } + /** * Constructs an operation from the parameters and adds it to the program * under construction. */ - private Op emit(Label label, OpCode opCode, Operand... args) { + private Op emit(ParserRuleContext ctx, Label label, OpCode opCode, Operand... args) { Op result = new Op(label, opCode, args); + result.setComment(ctx.getText()); this.prog.addInstr(result); return result; } @@ -96,8 +109,8 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { * Constructs an operation from the parameters and adds it to the program * under construction. */ - private Op emit(OpCode opCode, Operand... args) { - return emit((Label) null, opCode, args); + private Op emit(ParserRuleContext ctx, OpCode opCode, Operand... args) { + return emit(ctx, (Label) null, opCode, args); } @Override @@ -113,65 +126,134 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { return null; } + @Override + public Void visitProgram(ProgramContext ctx) { + emit(ctx, OpCode.loadI, new Num(0), tempArp); + emit(ctx, OpCode.loadI, new Num(0), arp); + + return visitChildren(ctx); + } + @Override public Void visitAssign(AssignContext ctx) { visit(ctx.singleExpr()); copyReg(ctx.singleExpr(), ctx); - switch (an.types.get(ctx)) { - case CHAR: - emit(OpCode.cstoreAI, getReg(ctx), zero, new Num(an.variables.get(ctx.variable()).getOffset())); - break; - default: - emit(OpCode.storeAI, getReg(ctx), zero, new Num(an.variables.get(ctx.variable()).getOffset())); + if (SimpleType.CHAR.equals(an.types.get(ctx))) + emit(ctx, OpCode.cstoreAI, getReg(ctx), getVar(ctx.variable(), an.variables.get(ctx.variable())), + new Num(an.variables.get(ctx.variable()).getOffset())); + else + emit(ctx, OpCode.storeAI, getReg(ctx), getVar(ctx.variable(), an.variables.get(ctx.variable())), + new Num(an.variables.get(ctx.variable()).getOffset())); + + return null; + } + + @Override + public Void visitCall(CallContext ctx) { + Variable function = an.variables.get(ctx.variable()); + FunctionType parameters = ((FunctionType) function.getType()); + Reg temp = new Reg("r__"); + visit(ctx.variable()); + emit(ctx.variable(), OpCode.loadAI, getVar(ctx.variable(), an.variables.get(ctx.variable())), + new Num(an.variables.get(ctx.variable()).getOffset()), temp); + emit(ctx.variable(), OpCode.push, temp); + + for (int i = 0; i < ctx.expr().size(); i++) { + visit(ctx.expr(i)); + + if (SimpleType.CHAR.equals(parameters.getParameters().get(i))) + emit(ctx.expr(i), OpCode.cpush, getReg(ctx.expr(i))); + else + emit(ctx.expr(i), OpCode.push, getReg(ctx.expr(i))); } + emit(ctx.variable(), OpCode.addI, arp, + new Num(((FunctionType) an.function.get(ctx).getType()).getLocalDataSize() + ARBASESIZE), tempArp); + for (int i = ctx.expr().size() - 1; i >= 0; i--) { + if (SimpleType.CHAR.equals(parameters.getParameters().get(i))) { + emit(ctx.expr(i), OpCode.cpop, temp); + emit(ctx.expr(i), OpCode.cstoreAI, temp, tempArp, new Num(parameters.getOffsets().get(i))); + } else { + emit(ctx.expr(i), OpCode.pop, temp); + emit(ctx.expr(i), OpCode.storeAI, temp, tempArp, new Num(parameters.getOffsets().get(i))); + } + } + emit(ctx.variable(), OpCode.storeAI, arp, tempArp, new Num(-4)); + Label label = new Label("ret" + ctx.hashCode()); + emit(ctx.variable(), OpCode.loadI, new Num(label), temp); + emit(ctx.variable(), OpCode.storeAI, temp, tempArp, new Num(-8)); + emit(ctx, OpCode.i2i, tempArp, arp); + emit(ctx.variable(), OpCode.pop, temp); + emit(ctx, OpCode.jump, temp); + emit(ctx, label, OpCode.loadAI, arp, new Num(-4), arp); + + an.registers.put(ctx, resultReg); + return null; + } + + @Override + public Void visitFuncDeclare(FuncDeclareContext ctx) { + Reg temp = new Reg("r__"); + Label skip = new Label("s" + ctx.hashCode()); + emit(ctx, OpCode.jumpI, skip); + int targetAddress = emit(ctx, OpCode.nop).getLine(); + visit(ctx.body); + copyReg(ctx.body, ctx); + if (SimpleType.CHAR.equals(an.types.get(ctx.body))) + emit(ctx, OpCode.c2c, getReg(ctx), resultReg); + else + emit(ctx, OpCode.i2i, getReg(ctx), resultReg); + emit(ctx, OpCode.loadAI, arp, new Num(-8), temp); + emit(ctx, OpCode.jump, temp); + emit(ctx, skip, OpCode.loadI, new Num(targetAddress), temp); + emit(ctx, OpCode.storeAI, temp, getVar(ctx, an.variables.get(ctx)), new Num(an.variables.get(ctx).getOffset())); return null; } @Override public Void visitBool(BoolContext ctx) { - emit(OpCode.loadI, new Num(ctx.TRUE() != null ? 1 : 0), getReg(ctx)); + emit(ctx, OpCode.loadI, new Num(ctx.TRUE() != null ? 1 : 0), getReg(ctx)); return null; } @Override public Void visitNumber(NumberContext ctx) { - emit(OpCode.loadI, new Num(Integer.parseInt(ctx.LITERAL10().getText())), getReg(ctx)); + emit(ctx, OpCode.loadI, new Num(Integer.parseInt(ctx.LITERAL10().getText())), getReg(ctx)); return null; } @Override public Void visitInfix1(Infix1Context ctx) { visitChildren(ctx); - emit(ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); + emit(ctx, ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); return null; } @Override public Void visitInfix2(Infix2Context ctx) { visitChildren(ctx); - emit(ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); + emit(ctx, ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); return null; } @Override public Void visitInfix3(Infix3Context ctx) { visitChildren(ctx); - emit(ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); + emit(ctx, ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); return null; } @Override public Void visitInfix4(Infix4Context ctx) { visitChildren(ctx); - emit(OpCode.and, getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); + emit(ctx, OpCode.and, getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); return null; } @Override public Void visitInfix5(Infix5Context ctx) { visitChildren(ctx); - emit(OpCode.or, getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); + emit(ctx, OpCode.or, getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx)); return null; } @@ -181,27 +263,27 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { switch (ctx.op.getType()) { case BasicLexer.MINUS: - emit(OpCode.rsubI, getReg(ctx.singleExpr()), new Num(0), getReg(ctx)); + emit(ctx, OpCode.rsubI, getReg(ctx.singleExpr()), new Num(0), getReg(ctx)); } return null; } @Override public Void visitVar(VarContext ctx) { - switch (an.types.get(ctx)) { - case CHAR: - emit(OpCode.cloadAI, zero, new Num(an.variables.get(ctx.variable()).getOffset()), getReg(ctx)); - break; - default: - emit(OpCode.loadAI, zero, new Num(an.variables.get(ctx.variable()).getOffset()), getReg(ctx)); - } + if (SimpleType.CHAR.equals(an.types.get(ctx))) + emit(ctx, OpCode.cloadAI, getVar(ctx.variable(), an.variables.get(ctx.variable())), + new Num(an.variables.get(ctx.variable()).getOffset()), getReg(ctx)); + else + emit(ctx, OpCode.loadAI, getVar(ctx.variable(), an.variables.get(ctx.variable())), + new Num(an.variables.get(ctx.variable()).getOffset()), getReg(ctx)); + return null; } @Override public Void visitChar(CharContext ctx) { - emit(OpCode.loadI, new Num(ctx.CHAR().getText().codePointAt(1)), getReg(ctx)); - emit(OpCode.i2c, getReg(ctx), getReg(ctx)); + emit(ctx, OpCode.loadI, new Num(ctx.CHAR().getText().codePointAt(1)), getReg(ctx)); + emit(ctx, OpCode.i2c, getReg(ctx), getReg(ctx)); return null; } @@ -209,38 +291,36 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { public Void visitRead(ReadContext ctx) { for (VariableContext expr : ctx.variable()) { visit(expr); - switch (an.types.get(expr)) { - case BOOL: - case INT: - emit(OpCode.in, new Str(""), getReg(ctx)); - emit(OpCode.storeAI, getReg(ctx), zero, new Num(an.variables.get(expr).getOffset())); - break; - case CHAR: + if (SimpleType.BOOL.equals(an.types.get(expr)) || SimpleType.INT.equals(an.types.get(expr))) { + emit(ctx, OpCode.in, new Str(""), getReg(ctx)); + emit(ctx, OpCode.storeAI, getReg(ctx), getVar(expr, an.variables.get(expr)), + new Num(an.variables.get(expr).getOffset())); + } else if (SimpleType.CHAR.equals(an.types.get(expr))) { // Get input until at least 1 character Label getTarget = new Label("lcin_l" + ctx.hashCode()); Label continueTarget = new Label("lcin_e" + ctx.hashCode()); Reg countReg = new Reg("tempReg"); - emit(getTarget, OpCode.cin, new Str("")); - emit(OpCode.pop, countReg); - emit(OpCode.cbr, countReg, continueTarget, getTarget); + emit(ctx, getTarget, OpCode.cin, new Str("")); + emit(ctx, OpCode.pop, countReg); + emit(ctx, OpCode.cbr, countReg, continueTarget, getTarget); // Get character - emit(continueTarget, OpCode.cpop, getReg(ctx)); - emit(OpCode.cstoreAI, getReg(ctx), zero, new Num(an.variables.get(expr).getOffset())); + emit(ctx, continueTarget, OpCode.cpop, getReg(ctx)); + emit(ctx, OpCode.cstoreAI, getReg(ctx), getVar(expr, an.variables.get(expr)), + new Num(an.variables.get(expr).getOffset())); // Pop all remaining characters Label loopTarget = new Label("lcpop_l" + ctx.hashCode()); Label iterTarget = new Label("lcpop_c" + ctx.hashCode()); Label stopTarget = new Label("lcpop_e" + ctx.hashCode()); Reg tempReg2 = new Reg("tempReg2"); - emit(loopTarget, OpCode.subI, countReg, new Num(1), countReg); - emit(OpCode.cbr, countReg, iterTarget, stopTarget); - emit(iterTarget, OpCode.cpop, tempReg2); - emit(OpCode.jumpI, loopTarget); - emit(stopTarget, OpCode.nop); - break; - default: - emit(OpCode.out, new Str("Unknown type: "), an.registers.get(expr)); + emit(ctx, loopTarget, OpCode.subI, countReg, new Num(1), countReg); + emit(ctx, OpCode.cbr, countReg, iterTarget, stopTarget); + emit(ctx, iterTarget, OpCode.cpop, tempReg2); + emit(ctx, OpCode.jumpI, loopTarget); + emit(ctx, stopTarget, OpCode.nop); + } else { + emit(ctx, OpCode.out, new Str("Unknown type: "), an.registers.get(expr)); } } return null; @@ -254,26 +334,26 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { visit(ctx.cond); if (ctx.onFalse == null) { - emit(OpCode.cbr, getReg(ctx.cond), toTrue, toEnd); + emit(ctx, OpCode.cbr, getReg(ctx.cond), toTrue, toEnd); - emit(toTrue, OpCode.nop); + emit(ctx, toTrue, OpCode.nop); visit(ctx.onTrue); } else { - emit(OpCode.cbr, getReg(ctx.cond), toTrue, toFalse); + emit(ctx, OpCode.cbr, getReg(ctx.cond), toTrue, toFalse); - emit(toTrue, OpCode.nop); + emit(ctx, toTrue, OpCode.nop); visit(ctx.onTrue); if (an.types.get(ctx) != SimpleType.VOID) - emit(OpCode.i2i, getReg(ctx.onTrue), getReg(ctx)); - emit(OpCode.jumpI, toEnd); + emit(ctx, OpCode.i2i, getReg(ctx.onTrue), getReg(ctx)); + emit(ctx, OpCode.jumpI, toEnd); - emit(toFalse, OpCode.nop); + emit(ctx, toFalse, OpCode.nop); visit(ctx.onFalse); if (an.types.get(ctx) != SimpleType.VOID) - emit(OpCode.i2i, getReg(ctx.onFalse), getReg(ctx)); + emit(ctx, OpCode.i2i, getReg(ctx.onFalse), getReg(ctx)); } - emit(toEnd, OpCode.nop); + emit(ctx, toEnd, OpCode.nop); return null; } @@ -284,13 +364,13 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { Label toCond = new Label("while_f" + ctx.hashCode()); Label toEnd = new Label("while_e" + ctx.hashCode()); - emit(OpCode.jumpI, toCond); - emit(toLoop, OpCode.nop); + emit(ctx, OpCode.jumpI, toCond); + emit(ctx, toLoop, OpCode.nop); visit(ctx.onTrue); - emit(toCond, OpCode.nop); + emit(ctx, toCond, OpCode.nop); visit(ctx.cond); - emit(OpCode.cbr, getReg(ctx.cond), toLoop, toEnd); - emit(toEnd, OpCode.nop); + emit(ctx, OpCode.cbr, getReg(ctx.cond), toLoop, toEnd); + emit(ctx, toEnd, OpCode.nop); return null; } @@ -299,20 +379,16 @@ public class BoppiBasicGenerator extends BasicBaseVisitor { public Void visitWrite(WriteContext ctx) { for (ExprContext expr : ctx.expr()) { visit(expr); - switch (an.types.get(expr)) { - case BOOL: - case INT: - emit(OpCode.out, new Str(""), getReg(expr)); - break; - case CHAR: + if (SimpleType.BOOL.equals(an.types.get(expr)) || SimpleType.INT.equals(an.types.get(expr))) { + emit(ctx, OpCode.out, new Str(""), getReg(expr)); + } else if (SimpleType.CHAR.equals(an.types.get(expr))) { Reg tempReg = new Reg("tempReg"); - emit(OpCode.cpush, getReg(expr)); - emit(OpCode.loadI, new Num(1), tempReg); - emit(OpCode.push, tempReg); - emit(OpCode.cout, new Str("")); - break; - default: - emit(OpCode.out, new Str("Unknown type: "), getReg(expr)); + emit(ctx, OpCode.cpush, getReg(expr)); + emit(ctx, OpCode.loadI, new Num(1), tempReg); + emit(ctx, OpCode.push, tempReg); + emit(ctx, OpCode.cout, new Str("")); + } else { + emit(ctx, OpCode.out, new Str("Unknown type: "), getReg(expr)); } } copyReg(ctx.expr(0), ctx); diff --git a/src/pp/s1184725/boppi/CachingSymbolTable.java b/src/pp/s1184725/boppi/CachingSymbolTable.java index efdba75..f3c71c7 100644 --- a/src/pp/s1184725/boppi/CachingSymbolTable.java +++ b/src/pp/s1184725/boppi/CachingSymbolTable.java @@ -13,11 +13,14 @@ import java.util.function.Supplier; * @param * the typing class */ -public class CachingSymbolTable { +public class CachingSymbolTable { protected Stack>> symbolMapStack; protected Stack offsets; + protected Stack functionSizes; protected Map> symbolCache; protected int offset; + protected int functionDepth; + protected int functionSize; /** * Creates an empty symbol table with no open scope. @@ -26,7 +29,10 @@ public class CachingSymbolTable { symbolMapStack = new Stack<>(); symbolCache = new HashMap<>(); offsets = new Stack<>(); + functionSizes = new Stack<>(); offset = 0; + functionDepth = 0; + functionSize = 0; } /** @@ -38,7 +44,19 @@ public class CachingSymbolTable { } /** - * Closes a lexical scope, removing all definitions within this scope. + * Opens a lexical scope for a function declaration, resetting the local + * offset and increasing the lookup depth. + */ + public void openFunctionScope() { + openScope(); + functionSizes.push(functionSize); + functionDepth++; + functionSize = 0; + offset = 0; + } + + /** + * Closes a lexical scope, removing all declarations within this scope. * * @throws EmptyStackException * if no scope is open @@ -55,11 +73,25 @@ public class CachingSymbolTable { offset = offsets.pop(); } + /** + * Closes a lexical scope for a function declaration, removing all + * declarations within this scope, restoring the local offset and decreasing + * the lookup depth. + * + * @throws EmptyStackException + * if no scope is open + */ + public void closeFunctionScope() throws EmptyStackException { + closeScope(); + functionSize = functionSizes.pop(); + functionDepth--; + } + /** * Opens a scope, executes the given code and closes the scope. This is a - * helper method to make sure {@link #openScope()} and {@link #closeScope()} - * calls are balanced. {@code code} must take no arguments and must return a - * value. + * helper method to make sure calls to {@link #openScope()} and + * {@link #closeScope()} are balanced. {@code code} must take no arguments + * and must return a value. * * @param * the type of the code's return value @@ -74,10 +106,30 @@ public class CachingSymbolTable { return result; } + /** + * Opens a function scope, executes the given code and closes it. This is a + * helper method to make sure calls to {@link #openFunctionScope()} and + * {@link #closeFunctionScope()} are balanced and returns the local data + * size (in bytes) of the function. {@code code} must take no arguments and + * must not return a value. + * + * @param code + * the code to execute within the scope + * @return the return value of the code + */ + public int withFunctionScope(Runnable code) { + openFunctionScope(); + code.run(); + int result = functionSize; + closeFunctionScope(); + return result; + } + /** * Associates an identifier with a certain type in the current lexical scope * and returns the newly made variable instance that belongs to this - * identifier. Throws an exception if the + * identifier. Throws an exception if the identifier is declared in this + * scope already. * * @param id * the name of the identifier @@ -93,20 +145,21 @@ public class CachingSymbolTable { if (symbolMapStack.peek().containsKey(id)) throw new Exception(String.format("Identifier '%s' already declared in this scope.", id)); - Variable var = new Variable<>(type, offset); - // TODO refactor to get type size - offset += ((SimpleType) type).getSize(); + Variable var = new Variable<>(type, functionDepth, offset); + offset += type.getSize(); + functionSize = Math.max(functionSize, offset); + symbolMapStack.peek().put(id, var); symbolCache.put(id, var); return var; } /** - * Returns whether the given identifier is defined. + * Returns whether the given identifier is declared. * * @param id * the name of the identifier - * @return true if the identifier has a defined type + * @return true if the identifier has a declared type * @throws EmptyStackException * if no scope is open */ @@ -124,14 +177,36 @@ public class CachingSymbolTable { * the name of the identifier * @return the type of the identifier * @throws Exception - * if the identifier is not defined + * if the identifier is not declared * @throws EmptyStackException * if no scope is open */ public Variable get(String id) throws Exception, EmptyStackException { if (!this.has(id)) - throw new Exception(String.format("Identifier '%s' is undefined.", id)); + throw new Exception(String.format("Identifier '%s' is undeclared.", id)); return symbolCache.get(id); } + + /** + * Returns the size, in bytes, required to store all the variables declared + * in the current function scope. Note that this is the size calculated up + * and including the last variable declaration, so make sure to call it + * right before leaving a function scope. + * + * @return the number of bytes required to store all variables local to a + * function + */ + public int getLocalDataSize() { + return functionSize; + } + + /** + * Returns the current lexical scope/function depth. + * + * @return the function depth + */ + public int getFunctionDepth() { + return functionDepth; + } } diff --git a/src/pp/s1184725/boppi/DebugCachingSymbolTable.java b/src/pp/s1184725/boppi/DebugCachingSymbolTable.java new file mode 100644 index 0000000..f133816 --- /dev/null +++ b/src/pp/s1184725/boppi/DebugCachingSymbolTable.java @@ -0,0 +1,57 @@ +package pp.s1184725.boppi; + +import java.util.EmptyStackException; + +public class DebugCachingSymbolTable extends CachingSymbolTable { + + @Override + public void openScope() { + super.openScope(); + } + + @Override + public void openFunctionScope() { + System.out.println(this.getClass().getName() + ": entering scope depth " + functionDepth); + super.openFunctionScope(); + } + + @Override + public void closeScope() throws EmptyStackException { + super.closeScope(); + } + + @Override + public void closeFunctionScope() throws EmptyStackException { + System.out.println(this.getClass().getName() + ": leaving scope depth " + functionDepth); + super.closeFunctionScope(); + } + + @Override + public Variable put(String id, T type) throws Exception, EmptyStackException { + System.out.println(this.getClass().getName() + ": declaring '" + id + "' at scope " + functionDepth); + return super.put(id, type); + } + + @Override + public boolean has(String id) throws EmptyStackException { + return super.has(id); + } + + @Override + public Variable get(String id) throws Exception, EmptyStackException { + System.out.println(this.getClass().getName() + ": retrieving '" + id + "' (depth " + + symbolCache.get(id).getDepth() + ") at scope " + functionDepth); + return super.get(id); + } + + @Override + public int getLocalDataSize() { + return super.getLocalDataSize(); + } + + @Override + public int getFunctionDepth() { + return super.getFunctionDepth(); + } + +} diff --git a/src/pp/s1184725/boppi/FunctionType.java b/src/pp/s1184725/boppi/FunctionType.java new file mode 100644 index 0000000..f7454c4 --- /dev/null +++ b/src/pp/s1184725/boppi/FunctionType.java @@ -0,0 +1,94 @@ +package pp.s1184725.boppi; + +import java.util.*; +import java.util.stream.Collectors; + +import pp.iloc.eval.Machine; + +public class FunctionType implements Type { + private List parameters; + private List offsets; + private Type result; + private int localDataSize; + private int depth; + + public FunctionType(Type returnType, List parameterTypes, int depth) { + result = returnType; + parameters = new ArrayList<>(parameterTypes); + offsets = new ArrayList<>(); + this.depth = depth; + } + + @Override + public int getSize() { + return Machine.INT_SIZE; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FunctionType)) + return false; + + FunctionType other = (FunctionType) obj; + return result.equals(other.result) && parameters.equals(other.parameters); + } + + @Override + public String toString() { + return parameters.stream().map(Type::toString).collect(Collectors.joining(",", "(", ")")) + "->" + + result.toString(); + } + + /** + * Sets the size (in bytes) of the local data segment for this function. + * + * @param newSize + * the size (in bytes) of the local data segment + */ + public void setLocalDataSize(int newSize) { + localDataSize = newSize; + } + + /** + * Returns the size (in bytes) of the local data segment for this function. + * + * @return the size (in bytes) of the local data segment + */ + public int getLocalDataSize() { + return localDataSize; + } + + /** + * Returns the result type of this function. + * + * @return the result type + */ + public Type getReturn() { + return result; + } + + /** + * Returns the parameter types of this function. + * + * @return the parameter types + */ + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public List getOffsets() { + return offsets; + } + + public int getDepth() { + return depth; + } + + public void setDepth(int newDepth) { + depth = newDepth; + } +} diff --git a/src/pp/s1184725/boppi/SimpleType.java b/src/pp/s1184725/boppi/SimpleType.java index 0ccc39a..ccfa52e 100644 --- a/src/pp/s1184725/boppi/SimpleType.java +++ b/src/pp/s1184725/boppi/SimpleType.java @@ -13,16 +13,12 @@ import pp.iloc.eval.Machine; *
  • void (empty/unit type)
  • * */ -public enum SimpleType { +public enum SimpleType implements Type { INT(Machine.INT_SIZE), CHAR(Machine.DEFAULT_CHAR_SIZE), BOOL(Machine.INT_SIZE), VOID(0); private final int size; - /** - * Gets the size of this data type. - * - * @return the size (in bytes) of this type - */ + @Override public int getSize() { return size; } @@ -39,7 +35,7 @@ public enum SimpleType { * @return the data type of the token, {@link SimpleType#VOID} if * unrecognized */ - public static SimpleType fromToken(int token) { + public static Type fromToken(int token) { switch (token) { case INTTYPE: return SimpleType.INT; diff --git a/src/pp/s1184725/boppi/ToolChain.java b/src/pp/s1184725/boppi/ToolChain.java index 2e4deaa..941c08b 100644 --- a/src/pp/s1184725/boppi/ToolChain.java +++ b/src/pp/s1184725/boppi/ToolChain.java @@ -208,7 +208,7 @@ public class ToolChain { try { s.run(); } catch (Exception e) { - logger.severe(e.getMessage()); + logger.severe(e.toString()); } } @@ -271,7 +271,7 @@ public class ToolChain { if (annotater.variables.get(ctx) != null) sb.append("var: " + escape(annotater.variables.get(ctx).toString()) + "
    "); if (annotater.types.get(ctx) != null) - sb.append("type: " + escape(annotater.types.get(ctx).name()) + "
    "); + sb.append("type: " + escape(annotater.types.get(ctx).toString()) + "
    "); sb.append(">;style=filled;fillcolor=\"" + hue + "+0.1+1\"]\n"); if (ctx.children != null) diff --git a/src/pp/s1184725/boppi/Type.java b/src/pp/s1184725/boppi/Type.java new file mode 100644 index 0000000..59c37f1 --- /dev/null +++ b/src/pp/s1184725/boppi/Type.java @@ -0,0 +1,12 @@ +package pp.s1184725.boppi; + +public interface Type { + + /** + * Gets the size of this data type. + * + * @return the size (in bytes) of this type + */ + int getSize(); + +} \ No newline at end of file diff --git a/src/pp/s1184725/boppi/Variable.java b/src/pp/s1184725/boppi/Variable.java index d876a68..0f7f47e 100644 --- a/src/pp/s1184725/boppi/Variable.java +++ b/src/pp/s1184725/boppi/Variable.java @@ -9,6 +9,7 @@ package pp.s1184725.boppi; */ public class Variable { private final T type; + private final int depth; private final int offset; /** @@ -19,8 +20,9 @@ public class Variable { * @param offset * the memory offset for this variable */ - public Variable(T type, int offset) { + public Variable(T type, int depth, int offset) { this.type = type; + this.depth = depth; this.offset = offset; } @@ -34,7 +36,7 @@ public class Variable { } /** - * Gets the memory offset of this variable instance. + * Gets the local data offset of this variable instance. * * @return the offset */ @@ -42,6 +44,15 @@ public class Variable { return offset; } + /** + * Gets the lexical depth of this variable instance. + * + * @return the depth + */ + public int getDepth() { + return depth; + } + @Override public String toString() { return String.format("%s:%X@%d", type.toString(), hashCode(), offset); diff --git a/src/pp/s1184725/boppi/test/CheckerTest.java b/src/pp/s1184725/boppi/test/CheckerTest.java index 3cf13a4..d060fa4 100644 --- a/src/pp/s1184725/boppi/test/CheckerTest.java +++ b/src/pp/s1184725/boppi/test/CheckerTest.java @@ -115,4 +115,40 @@ public class CheckerTest { checkFile("while.boppi"); assertThat(log, is(empty())); } + + @Test + public void correctFunctionTest() { + checkString("function int id(int a) a; 1"); + assertThat(log, is(empty())); + + checkString("function int id(int a) a; id(1); 1"); + assertThat(log, is(empty())); + + checkString("var int a; function int const(int b) a; 1"); + assertThat(log, is(empty())); + + checkString("function int add(int a, int b) a+b; print(add(4, 5)+1)"); + assertThat(log, is(empty())); + + checkString("function char const(char a, char b) a; print(const('A', 'T'))"); + assertThat(log, is(empty())); + + checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}"); + assertThat(log, is(empty())); + } + + @Test + public void wrongFunctionTest() { + checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)"); + assertThat(log, hasSize(1)); + assertThat(log.get(0).getLevel(), is(Level.SEVERE)); + + checkString("function char add(int a, int b) a+b; print(add(4, 5))"); + assertThat(log, hasSize(1)); + assertThat(log.get(0).getLevel(), is(Level.SEVERE)); + + checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)"); + assertThat(log, hasSize(1)); + assertThat(log.get(0).getLevel(), is(Level.SEVERE)); + } } diff --git a/src/pp/s1184725/boppi/test/GeneratorTest.java b/src/pp/s1184725/boppi/test/GeneratorTest.java index 1a2f220..ca31b64 100644 --- a/src/pp/s1184725/boppi/test/GeneratorTest.java +++ b/src/pp/s1184725/boppi/test/GeneratorTest.java @@ -10,6 +10,7 @@ import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.tree.ParseTree; import org.junit.Test; +import pp.iloc.Simulator; import pp.iloc.model.Program; import pp.s1184725.boppi.*; @@ -32,6 +33,10 @@ public class GeneratorTest { ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program(); Annotations annotations = ToolChain.getAnnotations(ast, logger); Program program = ToolChain.getILOC(ast, annotations); + + if (Simulator.DEBUG) + System.out.println(program.prettyPrint()); + out = ToolChain.execute(program, logger, input).split("\n"); } @@ -80,4 +85,38 @@ public class GeneratorTest { assertThat(log, is(empty())); assertThat(out, is(arrayContaining("13"))); } + + @Test + public void correctFunctionTest() { + compileAndRunString("function int id(int a) a; 1"); + assertThat(log, is(empty())); + + compileAndRunString("function int id(int a) a; id(1); 1"); + assertThat(log, is(empty())); + + compileAndRunString("var int a; function int const(int b) a; 1"); + assertThat(log, is(empty())); + + compileAndRunString("var int a; a := 1; function int const(int b) a; print(const(4))"); + assertThat(log, is(empty())); + assertThat(out, is(arrayContaining("1"))); + + compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)"); + assertThat(log, is(empty())); + assertThat(out, is(arrayContaining("10"))); + + compileAndRunString("function char const(char a, char b) a; print(const('A', 'T'))"); + assertThat(log, is(empty())); + assertThat(out, is(arrayContaining("A"))); + + compileAndRunString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}"); + assertThat(log, is(empty())); + + compileAndRunString( + "function int factorial(int n) {if (n > 1) then factorial(n-1)*n else 1 fi}; var int n; print(factorial(read(n)))", + "5"); + assertThat(log, is(empty())); + assertThat(out, is(arrayContaining("120"))); + } + }