From a06fe6e9891e8603a1c1b0ff6491e8d3ada5e32c Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 7 May 2017 11:58:54 +0200 Subject: [PATCH] Parsing, 3 Address Code, Type Inference --- src/dk/camelot64/kickc/parser/KickC.g4 | 22 +- src/dk/camelot64/kickc/parser/KickC.tokens | 83 +-- .../kickc/parser/KickCBaseListener.java | 84 +++ .../kickc/parser/KickCBaseVisitor.java | 49 ++ src/dk/camelot64/kickc/parser/KickCLexer.java | 232 ++++---- .../camelot64/kickc/parser/KickCLexer.tokens | 83 +-- .../camelot64/kickc/parser/KickCListener.java | 80 +++ .../camelot64/kickc/parser/KickCParser.java | 499 +++++++++++++++--- .../camelot64/kickc/parser/KickCVisitor.java | 47 ++ src/dk/camelot64/kickc/ssa/GenerateSSA.java | 155 ++++-- .../kickc/ssa/PassTypeInference.java | 84 +++ src/dk/camelot64/kickc/ssa/SSABasicBlock.java | 24 +- .../kickc/ssa/SSAConstantInteger.java | 4 + src/dk/camelot64/kickc/ssa/SSAJumpLabel.java | 16 + src/dk/camelot64/kickc/ssa/SSAOperator.java | 4 + src/dk/camelot64/kickc/ssa/SSASequence.java | 33 ++ src/dk/camelot64/kickc/ssa/SSAStatement.java | 44 +- .../kickc/ssa/SSAStatementAssignment.java | 66 +++ .../ssa/SSAStatementConditionalJump.java | 31 ++ .../camelot64/kickc/ssa/SSAStatementJump.java | 25 + .../kickc/ssa/SSAStatementJumpTarget.java | 24 + src/dk/camelot64/kickc/ssa/SSAVariable.java | 17 +- .../kickc/ssa/SSAVariableManager.java | 12 - src/dk/camelot64/kickc/ssa/Symbol.java | 43 ++ src/dk/camelot64/kickc/ssa/SymbolManager.java | 68 +++ src/dk/camelot64/kickc/ssa/SymbolType.java | 33 ++ src/dk/camelot64/kickc/test/main.java | 17 +- src/dk/camelot64/kickc/test/test.kc | 8 +- 28 files changed, 1543 insertions(+), 344 deletions(-) create mode 100644 src/dk/camelot64/kickc/ssa/PassTypeInference.java create mode 100644 src/dk/camelot64/kickc/ssa/SSAJumpLabel.java create mode 100644 src/dk/camelot64/kickc/ssa/SSASequence.java create mode 100644 src/dk/camelot64/kickc/ssa/SSAStatementAssignment.java create mode 100644 src/dk/camelot64/kickc/ssa/SSAStatementConditionalJump.java create mode 100644 src/dk/camelot64/kickc/ssa/SSAStatementJump.java create mode 100644 src/dk/camelot64/kickc/ssa/SSAStatementJumpTarget.java delete mode 100644 src/dk/camelot64/kickc/ssa/SSAVariableManager.java create mode 100644 src/dk/camelot64/kickc/ssa/Symbol.java create mode 100644 src/dk/camelot64/kickc/ssa/SymbolManager.java create mode 100644 src/dk/camelot64/kickc/ssa/SymbolType.java diff --git a/src/dk/camelot64/kickc/parser/KickC.g4 b/src/dk/camelot64/kickc/parser/KickC.g4 index aace994d0..791e091e2 100644 --- a/src/dk/camelot64/kickc/parser/KickC.g4 +++ b/src/dk/camelot64/kickc/parser/KickC.g4 @@ -1,11 +1,29 @@ // KickC grammar grammar KickC; + +file : + stmtSeq EOF + ; + +stmtSeq + : stmt+ + ; + +stmt + : '{' stmtSeq '}' #stmtBlock + | (TYPE)? NAME ('=' expr)? ';' #stmtAssignment + | expr ';' #stmtExpr + | 'if' '(' expr ')' stmt ( 'else' stmt )? #stmtIfElse + | 'while' '(' expr ')' stmt #stmtWhile + ; + + expr : '(' expr ')' #exprPar | ('+' | '-' | 'not' | '!') expr #exprUnary | expr ('*' | '/' ) expr #exprBinary | expr ( '+' | '-') expr #exprBinary - | expr ( '=' | '==' | '!=' | '<>' | '<' | '<=' | '=<' | '>=' | '=>' | '>' ) expr #exprBinary + | expr ( '==' | '!=' | '<>' | '<' | '<=' | '=<' | '>=' | '=>' | '>' ) expr #exprBinary | expr ( 'and' | '&&' ) expr #exprBinary | expr ( 'or' | '||' ) expr #exprBinary | NAME #exprId @@ -13,6 +31,8 @@ expr | STRING #exprString | BOOLEAN #exprBool ; + +TYPE: 'byte' | 'word' | 'string' | 'boolean'; STRING : '"' ('\\"' | ~'"')* '"'; BOOLEAN : 'true' | 'false'; NUMBER : NUMFLOAT | NUMINT ; diff --git a/src/dk/camelot64/kickc/parser/KickC.tokens b/src/dk/camelot64/kickc/parser/KickC.tokens index e5f7b36dd..69c474e0f 100644 --- a/src/dk/camelot64/kickc/parser/KickC.tokens +++ b/src/dk/camelot64/kickc/parser/KickC.tokens @@ -20,38 +20,51 @@ T__18=19 T__19=20 T__20=21 T__21=22 -STRING=23 -BOOLEAN=24 -NUMBER=25 -NUMFLOAT=26 -BINFLOAT=27 -DECFLOAT=28 -HEXFLOAT=29 -NUMINT=30 -BININTEGER=31 -DECINTEGER=32 -HEXINTEGER=33 -NAME=34 -WS=35 -'('=1 -')'=2 -'+'=3 -'-'=4 -'not'=5 -'!'=6 -'*'=7 -'/'=8 -'='=9 -'=='=10 -'!='=11 -'<>'=12 -'<'=13 -'<='=14 -'=<'=15 -'>='=16 -'=>'=17 -'>'=18 -'and'=19 -'&&'=20 -'or'=21 -'||'=22 +T__22=23 +T__23=24 +T__24=25 +T__25=26 +T__26=27 +T__27=28 +TYPE=29 +STRING=30 +BOOLEAN=31 +NUMBER=32 +NUMFLOAT=33 +BINFLOAT=34 +DECFLOAT=35 +HEXFLOAT=36 +NUMINT=37 +BININTEGER=38 +DECINTEGER=39 +HEXINTEGER=40 +NAME=41 +WS=42 +'{'=1 +'}'=2 +'='=3 +';'=4 +'if'=5 +'('=6 +')'=7 +'else'=8 +'while'=9 +'+'=10 +'-'=11 +'not'=12 +'!'=13 +'*'=14 +'/'=15 +'=='=16 +'!='=17 +'<>'=18 +'<'=19 +'<='=20 +'=<'=21 +'>='=22 +'=>'=23 +'>'=24 +'and'=25 +'&&'=26 +'or'=27 +'||'=28 diff --git a/src/dk/camelot64/kickc/parser/KickCBaseListener.java b/src/dk/camelot64/kickc/parser/KickCBaseListener.java index 532199b9f..dd59af9bd 100644 --- a/src/dk/camelot64/kickc/parser/KickCBaseListener.java +++ b/src/dk/camelot64/kickc/parser/KickCBaseListener.java @@ -11,6 +11,90 @@ import org.antlr.v4.runtime.tree.TerminalNode; * of the available methods. */ public class KickCBaseListener implements KickCListener { + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFile(KickCParser.FileContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFile(KickCParser.FileContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtSeq(KickCParser.StmtSeqContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtSeq(KickCParser.StmtSeqContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtBlock(KickCParser.StmtBlockContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtBlock(KickCParser.StmtBlockContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtAssignment(KickCParser.StmtAssignmentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtAssignment(KickCParser.StmtAssignmentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtExpr(KickCParser.StmtExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtExpr(KickCParser.StmtExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtIfElse(KickCParser.StmtIfElseContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtIfElse(KickCParser.StmtIfElseContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStmtWhile(KickCParser.StmtWhileContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStmtWhile(KickCParser.StmtWhileContext ctx) { } /** * {@inheritDoc} * diff --git a/src/dk/camelot64/kickc/parser/KickCBaseVisitor.java b/src/dk/camelot64/kickc/parser/KickCBaseVisitor.java index 808e94c75..01e0a560f 100644 --- a/src/dk/camelot64/kickc/parser/KickCBaseVisitor.java +++ b/src/dk/camelot64/kickc/parser/KickCBaseVisitor.java @@ -11,6 +11,55 @@ import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; * operations with no return type. */ public class KickCBaseVisitor extends AbstractParseTreeVisitor implements KickCVisitor { + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitFile(KickCParser.FileContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitStmtSeq(KickCParser.StmtSeqContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitStmtBlock(KickCParser.StmtBlockContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitStmtAssignment(KickCParser.StmtAssignmentContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitStmtExpr(KickCParser.StmtExprContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitStmtIfElse(KickCParser.StmtIfElseContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

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

+ */ + @Override public T visitStmtWhile(KickCParser.StmtWhileContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * diff --git a/src/dk/camelot64/kickc/parser/KickCLexer.java b/src/dk/camelot64/kickc/parser/KickCLexer.java index f29fae49a..57d8252cc 100644 --- a/src/dk/camelot64/kickc/parser/KickCLexer.java +++ b/src/dk/camelot64/kickc/parser/KickCLexer.java @@ -19,9 +19,10 @@ public class KickCLexer extends Lexer { 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, STRING=23, BOOLEAN=24, - NUMBER=25, NUMFLOAT=26, BINFLOAT=27, DECFLOAT=28, HEXFLOAT=29, NUMINT=30, - BININTEGER=31, DECINTEGER=32, HEXINTEGER=33, NAME=34, WS=35; + 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, TYPE=29, STRING=30, BOOLEAN=31, + NUMBER=32, NUMFLOAT=33, BINFLOAT=34, DECFLOAT=35, HEXFLOAT=36, NUMINT=37, + BININTEGER=38, DECINTEGER=39, HEXINTEGER=40, NAME=41, WS=42; public static String[] channelNames = { "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; @@ -33,22 +34,24 @@ public class KickCLexer extends Lexer { 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", "STRING", "BOOLEAN", "NUMBER", - "NUMFLOAT", "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER", - "DECINTEGER", "HEXINTEGER", "BINDIGIT", "DECDIGIT", "HEXDIGIT", "NAME", - "NAME_START", "NAME_CHAR", "WS" + "T__17", "T__18", "T__19", "T__20", "T__21", "T__22", "T__23", "T__24", + "T__25", "T__26", "T__27", "TYPE", "STRING", "BOOLEAN", "NUMBER", "NUMFLOAT", + "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER", "DECINTEGER", + "HEXINTEGER", "BINDIGIT", "DECDIGIT", "HEXDIGIT", "NAME", "NAME_START", + "NAME_CHAR", "WS" }; private static final String[] _LITERAL_NAMES = { - null, "'('", "')'", "'+'", "'-'", "'not'", "'!'", "'*'", "'/'", "'='", - "'=='", "'!='", "'<>'", "'<'", "'<='", "'=<'", "'>='", "'=>'", "'>'", - "'and'", "'&&'", "'or'", "'||'" + null, "'{'", "'}'", "'='", "';'", "'if'", "'('", "')'", "'else'", "'while'", + "'+'", "'-'", "'not'", "'!'", "'*'", "'/'", "'=='", "'!='", "'<>'", "'<'", + "'<='", "'=<'", "'>='", "'=>'", "'>'", "'and'", "'&&'", "'or'", "'||'" }; 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, "STRING", - "BOOLEAN", "NUMBER", "NUMFLOAT", "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", - "BININTEGER", "DECINTEGER", "HEXINTEGER", "NAME", "WS" + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, "TYPE", "STRING", "BOOLEAN", "NUMBER", "NUMFLOAT", + "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER", "DECINTEGER", + "HEXINTEGER", "NAME", "WS" }; public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); @@ -108,103 +111,122 @@ public class KickCLexer extends Lexer { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2%\u011b\b\1\4\2\t"+ + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2,\u0154\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)\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\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\13"+ - "\3\13\3\13\3\f\3\f\3\f\3\r\3\r\3\r\3\16\3\16\3\17\3\17\3\17\3\20\3\20"+ - "\3\20\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\3\24\3\24\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\30\7\30\u0092"+ - "\n\30\f\30\16\30\u0095\13\30\3\30\3\30\3\31\3\31\3\31\3\31\3\31\3\31\3"+ - "\31\3\31\3\31\5\31\u00a2\n\31\3\32\3\32\5\32\u00a6\n\32\3\33\3\33\3\33"+ - "\5\33\u00ab\n\33\3\34\3\34\3\34\3\34\3\34\5\34\u00b2\n\34\3\34\7\34\u00b5"+ - "\n\34\f\34\16\34\u00b8\13\34\3\34\3\34\6\34\u00bc\n\34\r\34\16\34\u00bd"+ - "\3\35\7\35\u00c1\n\35\f\35\16\35\u00c4\13\35\3\35\3\35\6\35\u00c8\n\35"+ - "\r\35\16\35\u00c9\3\36\3\36\3\36\3\36\3\36\5\36\u00d1\n\36\3\36\7\36\u00d4"+ - "\n\36\f\36\16\36\u00d7\13\36\3\36\3\36\6\36\u00db\n\36\r\36\16\36\u00dc"+ - "\3\37\3\37\3\37\5\37\u00e2\n\37\3 \3 \3 \6 \u00e7\n \r \16 \u00e8\3 \3"+ - " \6 \u00ed\n \r \16 \u00ee\5 \u00f1\n \3!\6!\u00f4\n!\r!\16!\u00f5\3\""+ - "\3\"\3\"\3\"\3\"\5\"\u00fd\n\"\3\"\6\"\u0100\n\"\r\"\16\"\u0101\3#\3#"+ - "\3$\3$\3%\3%\3&\3&\7&\u010c\n&\f&\16&\u010f\13&\3\'\3\'\3(\3(\3)\6)\u0116"+ - "\n)\r)\16)\u0117\3)\3)\2\2*\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25"+ + "\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\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3"+ + "\6\3\6\3\7\3\7\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\n\3\13"+ + "\3\13\3\f\3\f\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\21\3\22\3\22\3\22\3\23\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\32\3\32\3\33"+ + "\3\33\3\33\3\34\3\34\3\34\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\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3\36"+ + "\3\36\5\36\u00c5\n\36\3\37\3\37\3\37\3\37\7\37\u00cb\n\37\f\37\16\37\u00ce"+ + "\13\37\3\37\3\37\3 \3 \3 \3 \3 \3 \3 \3 \3 \5 \u00db\n \3!\3!\5!\u00df"+ + "\n!\3\"\3\"\3\"\5\"\u00e4\n\"\3#\3#\3#\3#\3#\5#\u00eb\n#\3#\7#\u00ee\n"+ + "#\f#\16#\u00f1\13#\3#\3#\6#\u00f5\n#\r#\16#\u00f6\3$\7$\u00fa\n$\f$\16"+ + "$\u00fd\13$\3$\3$\6$\u0101\n$\r$\16$\u0102\3%\3%\3%\3%\3%\5%\u010a\n%"+ + "\3%\7%\u010d\n%\f%\16%\u0110\13%\3%\3%\6%\u0114\n%\r%\16%\u0115\3&\3&"+ + "\3&\5&\u011b\n&\3\'\3\'\3\'\6\'\u0120\n\'\r\'\16\'\u0121\3\'\3\'\6\'\u0126"+ + "\n\'\r\'\16\'\u0127\5\'\u012a\n\'\3(\6(\u012d\n(\r(\16(\u012e\3)\3)\3"+ + ")\3)\3)\5)\u0136\n)\3)\6)\u0139\n)\r)\16)\u013a\3*\3*\3+\3+\3,\3,\3-\3"+ + "-\7-\u0145\n-\f-\16-\u0148\13-\3.\3.\3/\3/\3\60\6\60\u014f\n\60\r\60\16"+ + "\60\u0150\3\60\3\60\2\2\61\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\2G\2I\2K$M\2O\2Q%\3\2\n\3\2$$\4\2"+ - "DDdd\3\2\62\63\3\2\62;\5\2\62;CHch\5\2C\\aac|\6\2\62;C\\aac|\5\2\13\f"+ - "\17\17\"\"\2\u0130\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\2K"+ - "\3\2\2\2\2Q\3\2\2\2\3S\3\2\2\2\5U\3\2\2\2\7W\3\2\2\2\tY\3\2\2\2\13[\3"+ - "\2\2\2\r_\3\2\2\2\17a\3\2\2\2\21c\3\2\2\2\23e\3\2\2\2\25g\3\2\2\2\27j"+ - "\3\2\2\2\31m\3\2\2\2\33p\3\2\2\2\35r\3\2\2\2\37u\3\2\2\2!x\3\2\2\2#{\3"+ - "\2\2\2%~\3\2\2\2\'\u0080\3\2\2\2)\u0084\3\2\2\2+\u0087\3\2\2\2-\u008a"+ - "\3\2\2\2/\u008d\3\2\2\2\61\u00a1\3\2\2\2\63\u00a5\3\2\2\2\65\u00aa\3\2"+ - "\2\2\67\u00b1\3\2\2\29\u00c2\3\2\2\2;\u00d0\3\2\2\2=\u00e1\3\2\2\2?\u00f0"+ - "\3\2\2\2A\u00f3\3\2\2\2C\u00fc\3\2\2\2E\u0103\3\2\2\2G\u0105\3\2\2\2I"+ - "\u0107\3\2\2\2K\u0109\3\2\2\2M\u0110\3\2\2\2O\u0112\3\2\2\2Q\u0115\3\2"+ - "\2\2ST\7*\2\2T\4\3\2\2\2UV\7+\2\2V\6\3\2\2\2WX\7-\2\2X\b\3\2\2\2YZ\7/"+ - "\2\2Z\n\3\2\2\2[\\\7p\2\2\\]\7q\2\2]^\7v\2\2^\f\3\2\2\2_`\7#\2\2`\16\3"+ - "\2\2\2ab\7,\2\2b\20\3\2\2\2cd\7\61\2\2d\22\3\2\2\2ef\7?\2\2f\24\3\2\2"+ - "\2gh\7?\2\2hi\7?\2\2i\26\3\2\2\2jk\7#\2\2kl\7?\2\2l\30\3\2\2\2mn\7>\2"+ - "\2no\7@\2\2o\32\3\2\2\2pq\7>\2\2q\34\3\2\2\2rs\7>\2\2st\7?\2\2t\36\3\2"+ - "\2\2uv\7?\2\2vw\7>\2\2w \3\2\2\2xy\7@\2\2yz\7?\2\2z\"\3\2\2\2{|\7?\2\2"+ - "|}\7@\2\2}$\3\2\2\2~\177\7@\2\2\177&\3\2\2\2\u0080\u0081\7c\2\2\u0081"+ - "\u0082\7p\2\2\u0082\u0083\7f\2\2\u0083(\3\2\2\2\u0084\u0085\7(\2\2\u0085"+ - "\u0086\7(\2\2\u0086*\3\2\2\2\u0087\u0088\7q\2\2\u0088\u0089\7t\2\2\u0089"+ - ",\3\2\2\2\u008a\u008b\7~\2\2\u008b\u008c\7~\2\2\u008c.\3\2\2\2\u008d\u0093"+ - "\7$\2\2\u008e\u008f\7^\2\2\u008f\u0092\7$\2\2\u0090\u0092\n\2\2\2\u0091"+ - "\u008e\3\2\2\2\u0091\u0090\3\2\2\2\u0092\u0095\3\2\2\2\u0093\u0091\3\2"+ - "\2\2\u0093\u0094\3\2\2\2\u0094\u0096\3\2\2\2\u0095\u0093\3\2\2\2\u0096"+ - "\u0097\7$\2\2\u0097\60\3\2\2\2\u0098\u0099\7v\2\2\u0099\u009a\7t\2\2\u009a"+ - "\u009b\7w\2\2\u009b\u00a2\7g\2\2\u009c\u009d\7h\2\2\u009d\u009e\7c\2\2"+ - "\u009e\u009f\7n\2\2\u009f\u00a0\7u\2\2\u00a0\u00a2\7g\2\2\u00a1\u0098"+ - "\3\2\2\2\u00a1\u009c\3\2\2\2\u00a2\62\3\2\2\2\u00a3\u00a6\5\65\33\2\u00a4"+ - "\u00a6\5=\37\2\u00a5\u00a3\3\2\2\2\u00a5\u00a4\3\2\2\2\u00a6\64\3\2\2"+ - "\2\u00a7\u00ab\5\67\34\2\u00a8\u00ab\59\35\2\u00a9\u00ab\5;\36\2\u00aa"+ - "\u00a7\3\2\2\2\u00aa\u00a8\3\2\2\2\u00aa\u00a9\3\2\2\2\u00ab\66\3\2\2"+ - "\2\u00ac\u00b2\7\'\2\2\u00ad\u00ae\7\62\2\2\u00ae\u00b2\7d\2\2\u00af\u00b0"+ - "\7\62\2\2\u00b0\u00b2\7D\2\2\u00b1\u00ac\3\2\2\2\u00b1\u00ad\3\2\2\2\u00b1"+ - "\u00af\3\2\2\2\u00b2\u00b6\3\2\2\2\u00b3\u00b5\5E#\2\u00b4\u00b3\3\2\2"+ - "\2\u00b5\u00b8\3\2\2\2\u00b6\u00b4\3\2\2\2\u00b6\u00b7\3\2\2\2\u00b7\u00b9"+ - "\3\2\2\2\u00b8\u00b6\3\2\2\2\u00b9\u00bb\7\60\2\2\u00ba\u00bc\5E#\2\u00bb"+ - "\u00ba\3\2\2\2\u00bc\u00bd\3\2\2\2\u00bd\u00bb\3\2\2\2\u00bd\u00be\3\2"+ - "\2\2\u00be8\3\2\2\2\u00bf\u00c1\5G$\2\u00c0\u00bf\3\2\2\2\u00c1\u00c4"+ - "\3\2\2\2\u00c2\u00c0\3\2\2\2\u00c2\u00c3\3\2\2\2\u00c3\u00c5\3\2\2\2\u00c4"+ - "\u00c2\3\2\2\2\u00c5\u00c7\7\60\2\2\u00c6\u00c8\5G$\2\u00c7\u00c6\3\2"+ - "\2\2\u00c8\u00c9\3\2\2\2\u00c9\u00c7\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca"+ - ":\3\2\2\2\u00cb\u00d1\7&\2\2\u00cc\u00cd\7\62\2\2\u00cd\u00d1\7z\2\2\u00ce"+ - "\u00cf\7\62\2\2\u00cf\u00d1\7Z\2\2\u00d0\u00cb\3\2\2\2\u00d0\u00cc\3\2"+ - "\2\2\u00d0\u00ce\3\2\2\2\u00d1\u00d5\3\2\2\2\u00d2\u00d4\5I%\2\u00d3\u00d2"+ - "\3\2\2\2\u00d4\u00d7\3\2\2\2\u00d5\u00d3\3\2\2\2\u00d5\u00d6\3\2\2\2\u00d6"+ - "\u00d8\3\2\2\2\u00d7\u00d5\3\2\2\2\u00d8\u00da\7\60\2\2\u00d9\u00db\5"+ - "I%\2\u00da\u00d9\3\2\2\2\u00db\u00dc\3\2\2\2\u00dc\u00da\3\2\2\2\u00dc"+ - "\u00dd\3\2\2\2\u00dd<\3\2\2\2\u00de\u00e2\5A!\2\u00df\u00e2\5C\"\2\u00e0"+ - "\u00e2\5? \2\u00e1\u00de\3\2\2\2\u00e1\u00df\3\2\2\2\u00e1\u00e0\3\2\2"+ - "\2\u00e2>\3\2\2\2\u00e3\u00e4\7\62\2\2\u00e4\u00e6\t\3\2\2\u00e5\u00e7"+ - "\5E#\2\u00e6\u00e5\3\2\2\2\u00e7\u00e8\3\2\2\2\u00e8\u00e6\3\2\2\2\u00e8"+ - "\u00e9\3\2\2\2\u00e9\u00f1\3\2\2\2\u00ea\u00ec\7\'\2\2\u00eb\u00ed\5E"+ - "#\2\u00ec\u00eb\3\2\2\2\u00ed\u00ee\3\2\2\2\u00ee\u00ec\3\2\2\2\u00ee"+ - "\u00ef\3\2\2\2\u00ef\u00f1\3\2\2\2\u00f0\u00e3\3\2\2\2\u00f0\u00ea\3\2"+ - "\2\2\u00f1@\3\2\2\2\u00f2\u00f4\5G$\2\u00f3\u00f2\3\2\2\2\u00f4\u00f5"+ - "\3\2\2\2\u00f5\u00f3\3\2\2\2\u00f5\u00f6\3\2\2\2\u00f6B\3\2\2\2\u00f7"+ - "\u00fd\7&\2\2\u00f8\u00f9\7\62\2\2\u00f9\u00fd\7z\2\2\u00fa\u00fb\7\62"+ - "\2\2\u00fb\u00fd\7Z\2\2\u00fc\u00f7\3\2\2\2\u00fc\u00f8\3\2\2\2\u00fc"+ - "\u00fa\3\2\2\2\u00fd\u00ff\3\2\2\2\u00fe\u0100\5I%\2\u00ff\u00fe\3\2\2"+ - "\2\u0100\u0101\3\2\2\2\u0101\u00ff\3\2\2\2\u0101\u0102\3\2\2\2\u0102D"+ - "\3\2\2\2\u0103\u0104\t\4\2\2\u0104F\3\2\2\2\u0105\u0106\t\5\2\2\u0106"+ - "H\3\2\2\2\u0107\u0108\t\6\2\2\u0108J\3\2\2\2\u0109\u010d\5M\'\2\u010a"+ - "\u010c\5O(\2\u010b\u010a\3\2\2\2\u010c\u010f\3\2\2\2\u010d\u010b\3\2\2"+ - "\2\u010d\u010e\3\2\2\2\u010eL\3\2\2\2\u010f\u010d\3\2\2\2\u0110\u0111"+ - "\t\7\2\2\u0111N\3\2\2\2\u0112\u0113\t\b\2\2\u0113P\3\2\2\2\u0114\u0116"+ - "\t\t\2\2\u0115\u0114\3\2\2\2\u0116\u0117\3\2\2\2\u0117\u0115\3\2\2\2\u0117"+ - "\u0118\3\2\2\2\u0118\u0119\3\2\2\2\u0119\u011a\b)\2\2\u011aR\3\2\2\2\31"+ - "\2\u0091\u0093\u00a1\u00a5\u00aa\u00b1\u00b6\u00bd\u00c2\u00c9\u00d0\u00d5"+ - "\u00dc\u00e1\u00e8\u00ee\u00f0\u00f5\u00fc\u0101\u010d\u0117\3\b\2\2"; + "\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S\2U\2W\2Y+[\2]\2_,"+ + "\3\2\n\3\2$$\4\2DDdd\3\2\62\63\3\2\62;\5\2\62;CHch\5\2C\\aac|\6\2\62;"+ + "C\\aac|\5\2\13\f\17\17\"\"\2\u016c\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\2"+ + "O\3\2\2\2\2Q\3\2\2\2\2Y\3\2\2\2\2_\3\2\2\2\3a\3\2\2\2\5c\3\2\2\2\7e\3"+ + "\2\2\2\tg\3\2\2\2\13i\3\2\2\2\rl\3\2\2\2\17n\3\2\2\2\21p\3\2\2\2\23u\3"+ + "\2\2\2\25{\3\2\2\2\27}\3\2\2\2\31\177\3\2\2\2\33\u0083\3\2\2\2\35\u0085"+ + "\3\2\2\2\37\u0087\3\2\2\2!\u0089\3\2\2\2#\u008c\3\2\2\2%\u008f\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\u00a6\3\2\2\2\67\u00a9\3\2"+ + "\2\29\u00ac\3\2\2\2;\u00c4\3\2\2\2=\u00c6\3\2\2\2?\u00da\3\2\2\2A\u00de"+ + "\3\2\2\2C\u00e3\3\2\2\2E\u00ea\3\2\2\2G\u00fb\3\2\2\2I\u0109\3\2\2\2K"+ + "\u011a\3\2\2\2M\u0129\3\2\2\2O\u012c\3\2\2\2Q\u0135\3\2\2\2S\u013c\3\2"+ + "\2\2U\u013e\3\2\2\2W\u0140\3\2\2\2Y\u0142\3\2\2\2[\u0149\3\2\2\2]\u014b"+ + "\3\2\2\2_\u014e\3\2\2\2ab\7}\2\2b\4\3\2\2\2cd\7\177\2\2d\6\3\2\2\2ef\7"+ + "?\2\2f\b\3\2\2\2gh\7=\2\2h\n\3\2\2\2ij\7k\2\2jk\7h\2\2k\f\3\2\2\2lm\7"+ + "*\2\2m\16\3\2\2\2no\7+\2\2o\20\3\2\2\2pq\7g\2\2qr\7n\2\2rs\7u\2\2st\7"+ + "g\2\2t\22\3\2\2\2uv\7y\2\2vw\7j\2\2wx\7k\2\2xy\7n\2\2yz\7g\2\2z\24\3\2"+ + "\2\2{|\7-\2\2|\26\3\2\2\2}~\7/\2\2~\30\3\2\2\2\177\u0080\7p\2\2\u0080"+ + "\u0081\7q\2\2\u0081\u0082\7v\2\2\u0082\32\3\2\2\2\u0083\u0084\7#\2\2\u0084"+ + "\34\3\2\2\2\u0085\u0086\7,\2\2\u0086\36\3\2\2\2\u0087\u0088\7\61\2\2\u0088"+ + " \3\2\2\2\u0089\u008a\7?\2\2\u008a\u008b\7?\2\2\u008b\"\3\2\2\2\u008c"+ + "\u008d\7#\2\2\u008d\u008e\7?\2\2\u008e$\3\2\2\2\u008f\u0090\7>\2\2\u0090"+ + "\u0091\7@\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\7c\2\2\u00a3\u00a4\7p\2\2\u00a4\u00a5"+ + "\7f\2\2\u00a5\64\3\2\2\2\u00a6\u00a7\7(\2\2\u00a7\u00a8\7(\2\2\u00a8\66"+ + "\3\2\2\2\u00a9\u00aa\7q\2\2\u00aa\u00ab\7t\2\2\u00ab8\3\2\2\2\u00ac\u00ad"+ + "\7~\2\2\u00ad\u00ae\7~\2\2\u00ae:\3\2\2\2\u00af\u00b0\7d\2\2\u00b0\u00b1"+ + "\7{\2\2\u00b1\u00b2\7v\2\2\u00b2\u00c5\7g\2\2\u00b3\u00b4\7y\2\2\u00b4"+ + "\u00b5\7q\2\2\u00b5\u00b6\7t\2\2\u00b6\u00c5\7f\2\2\u00b7\u00b8\7u\2\2"+ + "\u00b8\u00b9\7v\2\2\u00b9\u00ba\7t\2\2\u00ba\u00bb\7k\2\2\u00bb\u00bc"+ + "\7p\2\2\u00bc\u00c5\7i\2\2\u00bd\u00be\7d\2\2\u00be\u00bf\7q\2\2\u00bf"+ + "\u00c0\7q\2\2\u00c0\u00c1\7n\2\2\u00c1\u00c2\7g\2\2\u00c2\u00c3\7c\2\2"+ + "\u00c3\u00c5\7p\2\2\u00c4\u00af\3\2\2\2\u00c4\u00b3\3\2\2\2\u00c4\u00b7"+ + "\3\2\2\2\u00c4\u00bd\3\2\2\2\u00c5<\3\2\2\2\u00c6\u00cc\7$\2\2\u00c7\u00c8"+ + "\7^\2\2\u00c8\u00cb\7$\2\2\u00c9\u00cb\n\2\2\2\u00ca\u00c7\3\2\2\2\u00ca"+ + "\u00c9\3\2\2\2\u00cb\u00ce\3\2\2\2\u00cc\u00ca\3\2\2\2\u00cc\u00cd\3\2"+ + "\2\2\u00cd\u00cf\3\2\2\2\u00ce\u00cc\3\2\2\2\u00cf\u00d0\7$\2\2\u00d0"+ + ">\3\2\2\2\u00d1\u00d2\7v\2\2\u00d2\u00d3\7t\2\2\u00d3\u00d4\7w\2\2\u00d4"+ + "\u00db\7g\2\2\u00d5\u00d6\7h\2\2\u00d6\u00d7\7c\2\2\u00d7\u00d8\7n\2\2"+ + "\u00d8\u00d9\7u\2\2\u00d9\u00db\7g\2\2\u00da\u00d1\3\2\2\2\u00da\u00d5"+ + "\3\2\2\2\u00db@\3\2\2\2\u00dc\u00df\5C\"\2\u00dd\u00df\5K&\2\u00de\u00dc"+ + "\3\2\2\2\u00de\u00dd\3\2\2\2\u00dfB\3\2\2\2\u00e0\u00e4\5E#\2\u00e1\u00e4"+ + "\5G$\2\u00e2\u00e4\5I%\2\u00e3\u00e0\3\2\2\2\u00e3\u00e1\3\2\2\2\u00e3"+ + "\u00e2\3\2\2\2\u00e4D\3\2\2\2\u00e5\u00eb\7\'\2\2\u00e6\u00e7\7\62\2\2"+ + "\u00e7\u00eb\7d\2\2\u00e8\u00e9\7\62\2\2\u00e9\u00eb\7D\2\2\u00ea\u00e5"+ + "\3\2\2\2\u00ea\u00e6\3\2\2\2\u00ea\u00e8\3\2\2\2\u00eb\u00ef\3\2\2\2\u00ec"+ + "\u00ee\5S*\2\u00ed\u00ec\3\2\2\2\u00ee\u00f1\3\2\2\2\u00ef\u00ed\3\2\2"+ + "\2\u00ef\u00f0\3\2\2\2\u00f0\u00f2\3\2\2\2\u00f1\u00ef\3\2\2\2\u00f2\u00f4"+ + "\7\60\2\2\u00f3\u00f5\5S*\2\u00f4\u00f3\3\2\2\2\u00f5\u00f6\3\2\2\2\u00f6"+ + "\u00f4\3\2\2\2\u00f6\u00f7\3\2\2\2\u00f7F\3\2\2\2\u00f8\u00fa\5U+\2\u00f9"+ + "\u00f8\3\2\2\2\u00fa\u00fd\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fb\u00fc\3\2"+ + "\2\2\u00fc\u00fe\3\2\2\2\u00fd\u00fb\3\2\2\2\u00fe\u0100\7\60\2\2\u00ff"+ + "\u0101\5U+\2\u0100\u00ff\3\2\2\2\u0101\u0102\3\2\2\2\u0102\u0100\3\2\2"+ + "\2\u0102\u0103\3\2\2\2\u0103H\3\2\2\2\u0104\u010a\7&\2\2\u0105\u0106\7"+ + "\62\2\2\u0106\u010a\7z\2\2\u0107\u0108\7\62\2\2\u0108\u010a\7Z\2\2\u0109"+ + "\u0104\3\2\2\2\u0109\u0105\3\2\2\2\u0109\u0107\3\2\2\2\u010a\u010e\3\2"+ + "\2\2\u010b\u010d\5W,\2\u010c\u010b\3\2\2\2\u010d\u0110\3\2\2\2\u010e\u010c"+ + "\3\2\2\2\u010e\u010f\3\2\2\2\u010f\u0111\3\2\2\2\u0110\u010e\3\2\2\2\u0111"+ + "\u0113\7\60\2\2\u0112\u0114\5W,\2\u0113\u0112\3\2\2\2\u0114\u0115\3\2"+ + "\2\2\u0115\u0113\3\2\2\2\u0115\u0116\3\2\2\2\u0116J\3\2\2\2\u0117\u011b"+ + "\5O(\2\u0118\u011b\5Q)\2\u0119\u011b\5M\'\2\u011a\u0117\3\2\2\2\u011a"+ + "\u0118\3\2\2\2\u011a\u0119\3\2\2\2\u011bL\3\2\2\2\u011c\u011d\7\62\2\2"+ + "\u011d\u011f\t\3\2\2\u011e\u0120\5S*\2\u011f\u011e\3\2\2\2\u0120\u0121"+ + "\3\2\2\2\u0121\u011f\3\2\2\2\u0121\u0122\3\2\2\2\u0122\u012a\3\2\2\2\u0123"+ + "\u0125\7\'\2\2\u0124\u0126\5S*\2\u0125\u0124\3\2\2\2\u0126\u0127\3\2\2"+ + "\2\u0127\u0125\3\2\2\2\u0127\u0128\3\2\2\2\u0128\u012a\3\2\2\2\u0129\u011c"+ + "\3\2\2\2\u0129\u0123\3\2\2\2\u012aN\3\2\2\2\u012b\u012d\5U+\2\u012c\u012b"+ + "\3\2\2\2\u012d\u012e\3\2\2\2\u012e\u012c\3\2\2\2\u012e\u012f\3\2\2\2\u012f"+ + "P\3\2\2\2\u0130\u0136\7&\2\2\u0131\u0132\7\62\2\2\u0132\u0136\7z\2\2\u0133"+ + "\u0134\7\62\2\2\u0134\u0136\7Z\2\2\u0135\u0130\3\2\2\2\u0135\u0131\3\2"+ + "\2\2\u0135\u0133\3\2\2\2\u0136\u0138\3\2\2\2\u0137\u0139\5W,\2\u0138\u0137"+ + "\3\2\2\2\u0139\u013a\3\2\2\2\u013a\u0138\3\2\2\2\u013a\u013b\3\2\2\2\u013b"+ + "R\3\2\2\2\u013c\u013d\t\4\2\2\u013dT\3\2\2\2\u013e\u013f\t\5\2\2\u013f"+ + "V\3\2\2\2\u0140\u0141\t\6\2\2\u0141X\3\2\2\2\u0142\u0146\5[.\2\u0143\u0145"+ + "\5]/\2\u0144\u0143\3\2\2\2\u0145\u0148\3\2\2\2\u0146\u0144\3\2\2\2\u0146"+ + "\u0147\3\2\2\2\u0147Z\3\2\2\2\u0148\u0146\3\2\2\2\u0149\u014a\t\7\2\2"+ + "\u014a\\\3\2\2\2\u014b\u014c\t\b\2\2\u014c^\3\2\2\2\u014d\u014f\t\t\2"+ + "\2\u014e\u014d\3\2\2\2\u014f\u0150\3\2\2\2\u0150\u014e\3\2\2\2\u0150\u0151"+ + "\3\2\2\2\u0151\u0152\3\2\2\2\u0152\u0153\b\60\2\2\u0153`\3\2\2\2\32\2"+ + "\u00c4\u00ca\u00cc\u00da\u00de\u00e3\u00ea\u00ef\u00f6\u00fb\u0102\u0109"+ + "\u010e\u0115\u011a\u0121\u0127\u0129\u012e\u0135\u013a\u0146\u0150\3\b"+ + "\2\2"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/dk/camelot64/kickc/parser/KickCLexer.tokens b/src/dk/camelot64/kickc/parser/KickCLexer.tokens index e5f7b36dd..69c474e0f 100644 --- a/src/dk/camelot64/kickc/parser/KickCLexer.tokens +++ b/src/dk/camelot64/kickc/parser/KickCLexer.tokens @@ -20,38 +20,51 @@ T__18=19 T__19=20 T__20=21 T__21=22 -STRING=23 -BOOLEAN=24 -NUMBER=25 -NUMFLOAT=26 -BINFLOAT=27 -DECFLOAT=28 -HEXFLOAT=29 -NUMINT=30 -BININTEGER=31 -DECINTEGER=32 -HEXINTEGER=33 -NAME=34 -WS=35 -'('=1 -')'=2 -'+'=3 -'-'=4 -'not'=5 -'!'=6 -'*'=7 -'/'=8 -'='=9 -'=='=10 -'!='=11 -'<>'=12 -'<'=13 -'<='=14 -'=<'=15 -'>='=16 -'=>'=17 -'>'=18 -'and'=19 -'&&'=20 -'or'=21 -'||'=22 +T__22=23 +T__23=24 +T__24=25 +T__25=26 +T__26=27 +T__27=28 +TYPE=29 +STRING=30 +BOOLEAN=31 +NUMBER=32 +NUMFLOAT=33 +BINFLOAT=34 +DECFLOAT=35 +HEXFLOAT=36 +NUMINT=37 +BININTEGER=38 +DECINTEGER=39 +HEXINTEGER=40 +NAME=41 +WS=42 +'{'=1 +'}'=2 +'='=3 +';'=4 +'if'=5 +'('=6 +')'=7 +'else'=8 +'while'=9 +'+'=10 +'-'=11 +'not'=12 +'!'=13 +'*'=14 +'/'=15 +'=='=16 +'!='=17 +'<>'=18 +'<'=19 +'<='=20 +'=<'=21 +'>='=22 +'=>'=23 +'>'=24 +'and'=25 +'&&'=26 +'or'=27 +'||'=28 diff --git a/src/dk/camelot64/kickc/parser/KickCListener.java b/src/dk/camelot64/kickc/parser/KickCListener.java index 6c8223fd9..dfce0dcdd 100644 --- a/src/dk/camelot64/kickc/parser/KickCListener.java +++ b/src/dk/camelot64/kickc/parser/KickCListener.java @@ -7,6 +7,86 @@ import org.antlr.v4.runtime.tree.ParseTreeListener; * {@link KickCParser}. */ public interface KickCListener extends ParseTreeListener { + /** + * Enter a parse tree produced by {@link KickCParser#file}. + * @param ctx the parse tree + */ + void enterFile(KickCParser.FileContext ctx); + /** + * Exit a parse tree produced by {@link KickCParser#file}. + * @param ctx the parse tree + */ + void exitFile(KickCParser.FileContext ctx); + /** + * Enter a parse tree produced by {@link KickCParser#stmtSeq}. + * @param ctx the parse tree + */ + void enterStmtSeq(KickCParser.StmtSeqContext ctx); + /** + * Exit a parse tree produced by {@link KickCParser#stmtSeq}. + * @param ctx the parse tree + */ + void exitStmtSeq(KickCParser.StmtSeqContext ctx); + /** + * Enter a parse tree produced by the {@code stmtBlock} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void enterStmtBlock(KickCParser.StmtBlockContext ctx); + /** + * Exit a parse tree produced by the {@code stmtBlock} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void exitStmtBlock(KickCParser.StmtBlockContext ctx); + /** + * Enter a parse tree produced by the {@code stmtAssignment} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void enterStmtAssignment(KickCParser.StmtAssignmentContext ctx); + /** + * Exit a parse tree produced by the {@code stmtAssignment} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void exitStmtAssignment(KickCParser.StmtAssignmentContext ctx); + /** + * Enter a parse tree produced by the {@code stmtExpr} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void enterStmtExpr(KickCParser.StmtExprContext ctx); + /** + * Exit a parse tree produced by the {@code stmtExpr} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void exitStmtExpr(KickCParser.StmtExprContext ctx); + /** + * Enter a parse tree produced by the {@code stmtIfElse} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void enterStmtIfElse(KickCParser.StmtIfElseContext ctx); + /** + * Exit a parse tree produced by the {@code stmtIfElse} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void exitStmtIfElse(KickCParser.StmtIfElseContext ctx); + /** + * Enter a parse tree produced by the {@code stmtWhile} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void enterStmtWhile(KickCParser.StmtWhileContext ctx); + /** + * Exit a parse tree produced by the {@code stmtWhile} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + */ + void exitStmtWhile(KickCParser.StmtWhileContext ctx); /** * Enter a parse tree produced by the {@code exprBinary} * labeled alternative in {@link KickCParser#expr}. diff --git a/src/dk/camelot64/kickc/parser/KickCParser.java b/src/dk/camelot64/kickc/parser/KickCParser.java index 0498deadb..44744aa15 100644 --- a/src/dk/camelot64/kickc/parser/KickCParser.java +++ b/src/dk/camelot64/kickc/parser/KickCParser.java @@ -19,25 +19,27 @@ public class KickCParser extends Parser { 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, STRING=23, BOOLEAN=24, - NUMBER=25, NUMFLOAT=26, BINFLOAT=27, DECFLOAT=28, HEXFLOAT=29, NUMINT=30, - BININTEGER=31, DECINTEGER=32, HEXINTEGER=33, NAME=34, WS=35; + 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, TYPE=29, STRING=30, BOOLEAN=31, + NUMBER=32, NUMFLOAT=33, BINFLOAT=34, DECFLOAT=35, HEXFLOAT=36, NUMINT=37, + BININTEGER=38, DECINTEGER=39, HEXINTEGER=40, NAME=41, WS=42; public static final int - RULE_expr = 0; + RULE_file = 0, RULE_stmtSeq = 1, RULE_stmt = 2, RULE_expr = 3; public static final String[] ruleNames = { - "expr" + "file", "stmtSeq", "stmt", "expr" }; private static final String[] _LITERAL_NAMES = { - null, "'('", "')'", "'+'", "'-'", "'not'", "'!'", "'*'", "'/'", "'='", - "'=='", "'!='", "'<>'", "'<'", "'<='", "'=<'", "'>='", "'=>'", "'>'", - "'and'", "'&&'", "'or'", "'||'" + null, "'{'", "'}'", "'='", "';'", "'if'", "'('", "')'", "'else'", "'while'", + "'+'", "'-'", "'not'", "'!'", "'*'", "'/'", "'=='", "'!='", "'<>'", "'<'", + "'<='", "'=<'", "'>='", "'=>'", "'>'", "'and'", "'&&'", "'or'", "'||'" }; 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, "STRING", - "BOOLEAN", "NUMBER", "NUMFLOAT", "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", - "BININTEGER", "DECINTEGER", "HEXINTEGER", "NAME", "WS" + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, "TYPE", "STRING", "BOOLEAN", "NUMBER", "NUMFLOAT", + "BINFLOAT", "DECFLOAT", "HEXFLOAT", "NUMINT", "BININTEGER", "DECINTEGER", + "HEXINTEGER", "NAME", "WS" }; public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); @@ -88,6 +90,350 @@ public class KickCParser extends Parser { super(input); _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); } + public static class FileContext extends ParserRuleContext { + public StmtSeqContext stmtSeq() { + return getRuleContext(StmtSeqContext.class,0); + } + public TerminalNode EOF() { return getToken(KickCParser.EOF, 0); } + public FileContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_file; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterFile(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitFile(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitFile(this); + else return visitor.visitChildren(this); + } + } + + public final FileContext file() throws RecognitionException { + FileContext _localctx = new FileContext(_ctx, getState()); + enterRule(_localctx, 0, RULE_file); + try { + enterOuterAlt(_localctx, 1); + { + setState(8); + stmtSeq(); + setState(9); + match(EOF); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class StmtSeqContext extends ParserRuleContext { + public List stmt() { + return getRuleContexts(StmtContext.class); + } + public StmtContext stmt(int i) { + return getRuleContext(StmtContext.class,i); + } + public StmtSeqContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_stmtSeq; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterStmtSeq(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitStmtSeq(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitStmtSeq(this); + else return visitor.visitChildren(this); + } + } + + public final StmtSeqContext stmtSeq() throws RecognitionException { + StmtSeqContext _localctx = new StmtSeqContext(_ctx, getState()); + enterRule(_localctx, 2, RULE_stmtSeq); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(12); + _errHandler.sync(this); + _la = _input.LA(1); + do { + { + { + setState(11); + stmt(); + } + } + setState(14); + _errHandler.sync(this); + _la = _input.LA(1); + } while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__0) | (1L << T__4) | (1L << T__5) | (1L << T__8) | (1L << T__9) | (1L << T__10) | (1L << T__11) | (1L << T__12) | (1L << TYPE) | (1L << STRING) | (1L << BOOLEAN) | (1L << NUMBER) | (1L << NAME))) != 0) ); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class StmtContext extends ParserRuleContext { + public StmtContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_stmt; } + + public StmtContext() { } + public void copyFrom(StmtContext ctx) { + super.copyFrom(ctx); + } + } + public static class StmtBlockContext extends StmtContext { + public StmtSeqContext stmtSeq() { + return getRuleContext(StmtSeqContext.class,0); + } + public StmtBlockContext(StmtContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterStmtBlock(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitStmtBlock(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitStmtBlock(this); + else return visitor.visitChildren(this); + } + } + public static class StmtExprContext extends StmtContext { + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public StmtExprContext(StmtContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterStmtExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitStmtExpr(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitStmtExpr(this); + else return visitor.visitChildren(this); + } + } + public static class StmtWhileContext extends StmtContext { + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public StmtContext stmt() { + return getRuleContext(StmtContext.class,0); + } + public StmtWhileContext(StmtContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterStmtWhile(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitStmtWhile(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitStmtWhile(this); + else return visitor.visitChildren(this); + } + } + public static class StmtAssignmentContext extends StmtContext { + public TerminalNode NAME() { return getToken(KickCParser.NAME, 0); } + public TerminalNode TYPE() { return getToken(KickCParser.TYPE, 0); } + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public StmtAssignmentContext(StmtContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterStmtAssignment(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitStmtAssignment(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitStmtAssignment(this); + else return visitor.visitChildren(this); + } + } + public static class StmtIfElseContext extends StmtContext { + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public List stmt() { + return getRuleContexts(StmtContext.class); + } + public StmtContext stmt(int i) { + return getRuleContext(StmtContext.class,i); + } + public StmtIfElseContext(StmtContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).enterStmtIfElse(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof KickCListener ) ((KickCListener)listener).exitStmtIfElse(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof KickCVisitor ) return ((KickCVisitor)visitor).visitStmtIfElse(this); + else return visitor.visitChildren(this); + } + } + + public final StmtContext stmt() throws RecognitionException { + StmtContext _localctx = new StmtContext(_ctx, getState()); + enterRule(_localctx, 4, RULE_stmt); + int _la; + try { + setState(47); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { + case 1: + _localctx = new StmtBlockContext(_localctx); + enterOuterAlt(_localctx, 1); + { + setState(16); + match(T__0); + setState(17); + stmtSeq(); + setState(18); + match(T__1); + } + break; + case 2: + _localctx = new StmtAssignmentContext(_localctx); + enterOuterAlt(_localctx, 2); + { + setState(21); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==TYPE) { + { + setState(20); + match(TYPE); + } + } + + setState(23); + match(NAME); + setState(26); + _errHandler.sync(this); + _la = _input.LA(1); + if (_la==T__2) { + { + setState(24); + match(T__2); + setState(25); + expr(0); + } + } + + setState(28); + match(T__3); + } + break; + case 3: + _localctx = new StmtExprContext(_localctx); + enterOuterAlt(_localctx, 3); + { + setState(29); + expr(0); + setState(30); + match(T__3); + } + break; + case 4: + _localctx = new StmtIfElseContext(_localctx); + enterOuterAlt(_localctx, 4); + { + setState(32); + match(T__4); + setState(33); + match(T__5); + setState(34); + expr(0); + setState(35); + match(T__6); + setState(36); + stmt(); + setState(39); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) { + case 1: + { + setState(37); + match(T__7); + setState(38); + stmt(); + } + break; + } + } + break; + case 5: + _localctx = new StmtWhileContext(_localctx); + enterOuterAlt(_localctx, 5); + { + setState(41); + match(T__8); + setState(42); + match(T__5); + setState(43); + expr(0); + setState(44); + match(T__6); + setState(45); + stmt(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + public static class ExprContext extends ParserRuleContext { public ExprContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -237,41 +583,41 @@ public class KickCParser extends Parser { int _parentState = getState(); ExprContext _localctx = new ExprContext(_ctx, _parentState); ExprContext _prevctx = _localctx; - int _startState = 0; - enterRecursionRule(_localctx, 0, RULE_expr, _p); + int _startState = 6; + enterRecursionRule(_localctx, 6, RULE_expr, _p); int _la; try { int _alt; enterOuterAlt(_localctx, 1); { - setState(13); + setState(60); _errHandler.sync(this); switch (_input.LA(1)) { - case T__0: + case T__5: { _localctx = new ExprParContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(3); - match(T__0); - setState(4); + setState(50); + match(T__5); + setState(51); expr(0); - setState(5); - match(T__1); + setState(52); + match(T__6); } break; - case T__2: - case T__3: - case T__4: - case T__5: + case T__9: + case T__10: + case T__11: + case T__12: { _localctx = new ExprUnaryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(7); + setState(54); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__2) | (1L << T__3) | (1L << T__4) | (1L << T__5))) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__9) | (1L << T__10) | (1L << T__11) | (1L << T__12))) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -279,7 +625,7 @@ public class KickCParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(8); + setState(55); expr(10); } break; @@ -288,7 +634,7 @@ public class KickCParser extends Parser { _localctx = new ExprIdContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(9); + setState(56); match(NAME); } break; @@ -297,7 +643,7 @@ public class KickCParser extends Parser { _localctx = new ExprNumberContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(10); + setState(57); match(NUMBER); } break; @@ -306,7 +652,7 @@ public class KickCParser extends Parser { _localctx = new ExprStringContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(11); + setState(58); match(STRING); } break; @@ -315,7 +661,7 @@ public class KickCParser extends Parser { _localctx = new ExprBoolContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(12); + setState(59); match(BOOLEAN); } break; @@ -323,26 +669,26 @@ public class KickCParser extends Parser { throw new NoViableAltException(this); } _ctx.stop = _input.LT(-1); - setState(32); + setState(79); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,2,_ctx); + _alt = getInterpreter().adaptivePredict(_input,7,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(30); + setState(77); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) { case 1: { _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(15); + setState(62); if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); - setState(16); + setState(63); _la = _input.LA(1); - if ( !(_la==T__6 || _la==T__7) ) { + if ( !(_la==T__13 || _la==T__14) ) { _errHandler.recoverInline(this); } else { @@ -350,7 +696,7 @@ public class KickCParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(17); + setState(64); expr(10); } break; @@ -358,11 +704,11 @@ public class KickCParser extends Parser { { _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(18); + setState(65); if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)"); - setState(19); + setState(66); _la = _input.LA(1); - if ( !(_la==T__2 || _la==T__3) ) { + if ( !(_la==T__9 || _la==T__10) ) { _errHandler.recoverInline(this); } else { @@ -370,7 +716,7 @@ public class KickCParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(20); + setState(67); expr(9); } break; @@ -378,11 +724,11 @@ public class KickCParser extends Parser { { _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(21); + setState(68); if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)"); - setState(22); + setState(69); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__8) | (1L << T__9) | (1L << T__10) | (1L << T__11) | (1L << T__12) | (1L << T__13) | (1L << T__14) | (1L << T__15) | (1L << T__16) | (1L << T__17))) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__15) | (1L << T__16) | (1L << T__17) | (1L << T__18) | (1L << T__19) | (1L << T__20) | (1L << T__21) | (1L << T__22) | (1L << T__23))) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -390,7 +736,7 @@ public class KickCParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(23); + setState(70); expr(8); } break; @@ -398,11 +744,11 @@ public class KickCParser extends Parser { { _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(24); + setState(71); if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); - setState(25); + setState(72); _la = _input.LA(1); - if ( !(_la==T__18 || _la==T__19) ) { + if ( !(_la==T__24 || _la==T__25) ) { _errHandler.recoverInline(this); } else { @@ -410,7 +756,7 @@ public class KickCParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(26); + setState(73); expr(7); } break; @@ -418,11 +764,11 @@ public class KickCParser extends Parser { { _localctx = new ExprBinaryContext(new ExprContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expr); - setState(27); + setState(74); if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); - setState(28); + setState(75); _la = _input.LA(1); - if ( !(_la==T__20 || _la==T__21) ) { + if ( !(_la==T__26 || _la==T__27) ) { _errHandler.recoverInline(this); } else { @@ -430,16 +776,16 @@ public class KickCParser extends Parser { _errHandler.reportMatch(this); consume(); } - setState(29); + setState(76); expr(6); } break; } } } - setState(34); + setState(81); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,2,_ctx); + _alt = getInterpreter().adaptivePredict(_input,7,_ctx); } } } @@ -456,7 +802,7 @@ public class KickCParser extends Parser { public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { switch (ruleIndex) { - case 0: + case 3: return expr_sempred((ExprContext)_localctx, predIndex); } return true; @@ -478,19 +824,30 @@ public class KickCParser extends Parser { } public static final String _serializedATN = - "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3%&\4\2\t\2\3\2\3\2"+ - "\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\5\2\20\n\2\3\2\3\2\3\2\3\2\3\2\3"+ - "\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\2\7\2!\n\2\f\2\16\2$\13\2\3\2\2\3"+ - "\2\3\2\2\b\3\2\5\b\3\2\t\n\3\2\5\6\3\2\13\24\3\2\25\26\3\2\27\30\2.\2"+ - "\17\3\2\2\2\4\5\b\2\1\2\5\6\7\3\2\2\6\7\5\2\2\2\7\b\7\4\2\2\b\20\3\2\2"+ - "\2\t\n\t\2\2\2\n\20\5\2\2\f\13\20\7$\2\2\f\20\7\33\2\2\r\20\7\31\2\2\16"+ - "\20\7\32\2\2\17\4\3\2\2\2\17\t\3\2\2\2\17\13\3\2\2\2\17\f\3\2\2\2\17\r"+ - "\3\2\2\2\17\16\3\2\2\2\20\"\3\2\2\2\21\22\f\13\2\2\22\23\t\3\2\2\23!\5"+ - "\2\2\f\24\25\f\n\2\2\25\26\t\4\2\2\26!\5\2\2\13\27\30\f\t\2\2\30\31\t"+ - "\5\2\2\31!\5\2\2\n\32\33\f\b\2\2\33\34\t\6\2\2\34!\5\2\2\t\35\36\f\7\2"+ - "\2\36\37\t\7\2\2\37!\5\2\2\b \21\3\2\2\2 \24\3\2\2\2 \27\3\2\2\2 \32\3"+ - "\2\2\2 \35\3\2\2\2!$\3\2\2\2\" \3\2\2\2\"#\3\2\2\2#\3\3\2\2\2$\"\3\2\2"+ - "\2\5\17 \""; + "\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\3\2\3\2\3\2\3\3\6\3\17\n\3\r\3\16\3\20\3\4\3\4\3\4\3"+ + "\4\3\4\5\4\30\n\4\3\4\3\4\3\4\5\4\35\n\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3"+ + "\4\3\4\3\4\3\4\5\4*\n\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4\62\n\4\3\5\3\5\3\5"+ + "\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\5\5?\n\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5"+ + "\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\7\5P\n\5\f\5\16\5S\13\5\3\5\2\3\b\6\2"+ + "\4\6\b\2\b\3\2\f\17\3\2\20\21\3\2\f\r\3\2\22\32\3\2\33\34\3\2\35\36\2"+ + "b\2\n\3\2\2\2\4\16\3\2\2\2\6\61\3\2\2\2\b>\3\2\2\2\n\13\5\4\3\2\13\f\7"+ + "\2\2\3\f\3\3\2\2\2\r\17\5\6\4\2\16\r\3\2\2\2\17\20\3\2\2\2\20\16\3\2\2"+ + "\2\20\21\3\2\2\2\21\5\3\2\2\2\22\23\7\3\2\2\23\24\5\4\3\2\24\25\7\4\2"+ + "\2\25\62\3\2\2\2\26\30\7\37\2\2\27\26\3\2\2\2\27\30\3\2\2\2\30\31\3\2"+ + "\2\2\31\34\7+\2\2\32\33\7\5\2\2\33\35\5\b\5\2\34\32\3\2\2\2\34\35\3\2"+ + "\2\2\35\36\3\2\2\2\36\62\7\6\2\2\37 \5\b\5\2 !\7\6\2\2!\62\3\2\2\2\"#"+ + "\7\7\2\2#$\7\b\2\2$%\5\b\5\2%&\7\t\2\2&)\5\6\4\2\'(\7\n\2\2(*\5\6\4\2"+ + ")\'\3\2\2\2)*\3\2\2\2*\62\3\2\2\2+,\7\13\2\2,-\7\b\2\2-.\5\b\5\2./\7\t"+ + "\2\2/\60\5\6\4\2\60\62\3\2\2\2\61\22\3\2\2\2\61\27\3\2\2\2\61\37\3\2\2"+ + "\2\61\"\3\2\2\2\61+\3\2\2\2\62\7\3\2\2\2\63\64\b\5\1\2\64\65\7\b\2\2\65"+ + "\66\5\b\5\2\66\67\7\t\2\2\67?\3\2\2\289\t\2\2\29?\5\b\5\f:?\7+\2\2;?\7"+ + "\"\2\2\63\3\2\2\2>8\3\2\2\2>:\3\2\2\2>;\3\2\2\2><\3"+ + "\2\2\2>=\3\2\2\2?Q\3\2\2\2@A\f\13\2\2AB\t\3\2\2BP\5\b\5\fCD\f\n\2\2DE"+ + "\t\4\2\2EP\5\b\5\13FG\f\t\2\2GH\t\5\2\2HP\5\b\5\nIJ\f\b\2\2JK\t\6\2\2"+ + "KP\5\b\5\tLM\f\7\2\2MN\t\7\2\2NP\5\b\5\bO@\3\2\2\2OC\3\2\2\2OF\3\2\2\2"+ + "OI\3\2\2\2OL\3\2\2\2PS\3\2\2\2QO\3\2\2\2QR\3\2\2\2R\t\3\2\2\2SQ\3\2\2"+ + "\2\n\20\27\34)\61>OQ"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/src/dk/camelot64/kickc/parser/KickCVisitor.java b/src/dk/camelot64/kickc/parser/KickCVisitor.java index 969d3ace7..ccafef85a 100644 --- a/src/dk/camelot64/kickc/parser/KickCVisitor.java +++ b/src/dk/camelot64/kickc/parser/KickCVisitor.java @@ -10,6 +10,53 @@ import org.antlr.v4.runtime.tree.ParseTreeVisitor; * operations with no return type. */ public interface KickCVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by {@link KickCParser#file}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFile(KickCParser.FileContext ctx); + /** + * Visit a parse tree produced by {@link KickCParser#stmtSeq}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtSeq(KickCParser.StmtSeqContext ctx); + /** + * Visit a parse tree produced by the {@code stmtBlock} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtBlock(KickCParser.StmtBlockContext ctx); + /** + * Visit a parse tree produced by the {@code stmtAssignment} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtAssignment(KickCParser.StmtAssignmentContext ctx); + /** + * Visit a parse tree produced by the {@code stmtExpr} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtExpr(KickCParser.StmtExprContext ctx); + /** + * Visit a parse tree produced by the {@code stmtIfElse} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtIfElse(KickCParser.StmtIfElseContext ctx); + /** + * Visit a parse tree produced by the {@code stmtWhile} + * labeled alternative in {@link KickCParser#stmt}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStmtWhile(KickCParser.StmtWhileContext ctx); /** * Visit a parse tree produced by the {@code exprBinary} * labeled alternative in {@link KickCParser#expr}. diff --git a/src/dk/camelot64/kickc/ssa/GenerateSSA.java b/src/dk/camelot64/kickc/ssa/GenerateSSA.java index 55223b377..64c710541 100644 --- a/src/dk/camelot64/kickc/ssa/GenerateSSA.java +++ b/src/dk/camelot64/kickc/ssa/GenerateSSA.java @@ -5,16 +5,110 @@ import dk.camelot64.kickc.parser.KickCParser; import org.antlr.v4.runtime.tree.TerminalNode; /** Generates program SSA form by visiting the ANTLR4 parse tree*/ -public class GenerateSSA extends KickCBaseVisitor { +public class GenerateSSA extends KickCBaseVisitor { - SSAVariableManager variableManager; + private SymbolManager symbolManager; + private SSASequence sequence; - public GenerateSSA(SSAVariableManager variableManager) { - this.variableManager = variableManager; + public GenerateSSA() { + this.symbolManager = new SymbolManager(); + this.sequence = new SSASequence(); } @Override - public SSAFragment visitExprNumber(KickCParser.ExprNumberContext ctx) { + public SSARValue visitFile(KickCParser.FileContext ctx) { + this.visit(ctx.stmtSeq()); + return null; + } + + + @Override + public SSARValue visitStmtSeq(KickCParser.StmtSeqContext ctx) { + for(int i=0; i { } @Override - public SSAFragment visitExprString(KickCParser.ExprStringContext ctx) { + public SSARValue visitExprString(KickCParser.ExprStringContext ctx) { return new SSAConstantString(ctx.getText()); } @Override - public SSAFragment visitExprBool(KickCParser.ExprBoolContext ctx) { + public SSARValue visitExprBool(KickCParser.ExprBoolContext ctx) { String bool = ctx.getText(); - return new SSAConstantBool(new Boolean(bool)); + return new SSAConstantBool(Boolean.valueOf(bool)); } @Override - public SSAFragment visitExprBinary(KickCParser.ExprBinaryContext ctx) { - SSAFragment left = this.visit(ctx.expr(0)); - SSAFragment right = this.visit(ctx.expr(1)); + public SSARValue visitExprBinary(KickCParser.ExprBinaryContext ctx) { + SSARValue left = this.visit(ctx.expr(0)); + SSARValue right = this.visit(ctx.expr(1)); String op = ((TerminalNode)ctx.getChild(1)).getSymbol().getText(); SSAOperator operator = new SSAOperator(op); - SSAVariable tmpVar = variableManager.generateIntermediateVariable(); - SSAStatement stmt = new SSAStatement(tmpVar, getSSARValue(left), operator, getSSARValue(right)); - System.out.println(stmt); - return stmt; + Symbol tmpVar = symbolManager.newIntermediateAssignment(); + SSAStatement stmt = new SSAStatementAssignment(tmpVar, left, operator, right); + sequence.addStatement(stmt); + return tmpVar; } @Override - public SSAFragment visitExprUnary(KickCParser.ExprUnaryContext ctx) { - SSAFragment child = this.visit(ctx.expr()); + public SSARValue visitExprUnary(KickCParser.ExprUnaryContext ctx) { + SSARValue child = this.visit(ctx.expr()); String op = ((TerminalNode)ctx.getChild(0)).getSymbol().getText(); SSAOperator operator = new SSAOperator(op); - SSAVariable tmpVar = variableManager.generateIntermediateVariable(); - SSAStatement stmt = new SSAStatement(tmpVar, operator, getSSARValue(child)); - System.out.println(stmt); - return stmt; + Symbol tmpVar = symbolManager.newIntermediateAssignment(); + SSAStatement stmt = new SSAStatementAssignment(tmpVar, operator, child); + sequence.addStatement(stmt); + return tmpVar; } @Override - public SSAFragment visitExprPar(KickCParser.ExprParContext ctx) { + public SSARValue visitExprPar(KickCParser.ExprParContext ctx) { return this.visit(ctx.expr()); } - SSARValue getSSARValue(SSAFragment ssaFragment) { - if(ssaFragment instanceof SSARValue) { - return (SSARValue) ssaFragment; - } if(ssaFragment instanceof SSAStatement) { - SSAStatement ssaStatement = (SSAStatement) ssaFragment; - return (SSARValue) ssaStatement.getlValue(); - } - throw new RuntimeException("Cannot extract SSA RValue"); + @Override + public SSARValue visitExprId(KickCParser.ExprIdContext ctx) { + return symbolManager.newVariableUsage(ctx.NAME().getText()); } + public SSASequence getSequence() { + return sequence; + } + public SymbolManager getSymbols() { + return this.symbolManager; + } } diff --git a/src/dk/camelot64/kickc/ssa/PassTypeInference.java b/src/dk/camelot64/kickc/ssa/PassTypeInference.java new file mode 100644 index 000000000..41b52efcd --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/PassTypeInference.java @@ -0,0 +1,84 @@ +package dk.camelot64.kickc.ssa; + +/** + * Pass through the SSA statements inferring types of unresolved variables. + */ +public class PassTypeInference { + + public void inferTypes(SSASequence sequence, SymbolManager symbols) { + for (SSAStatement statement : sequence.getStatements()) { + if (statement instanceof SSAStatementAssignment) { + SSAStatementAssignment assignment = (SSAStatementAssignment) statement; + Symbol symbol = (Symbol) assignment.getlValue(); + if (SymbolType.VAR.equals(symbol.getType())) { + // Unresolved symbol - perform inference + SSAOperator operator = assignment.getOperator(); + if (operator == null || assignment.getRValue1() == null) { + // Copy operation or Unary operation + SSARValue rValue = assignment.getRValue2(); + SymbolType type = inferType(rValue); + symbol.setInferredType(type); + } else { + // Binary operation + SymbolType type1 = inferType(assignment.getRValue1()); + SymbolType type2 = inferType(assignment.getRValue2()); + SymbolType type = inferType(type1, operator, type2); + symbol.setInferredType(type); + } + } + } + } + } + + private SymbolType inferType(SymbolType type1, SSAOperator operator, SymbolType type2) { + String op = operator.getOperator(); + switch (op) { + case "==": + case "<": + case "<=": + case "=<": + case ">": + case ">=": + case "=>": + case "<>": + case "!=": + case "&&": + case "||": + case "and": + case "or": + return SymbolType.BOOLEAN; + case "+": + case "-": + case "*": + case "/": + if (type1.equals(SymbolType.WORD) || type2.equals(SymbolType.WORD)) { + return SymbolType.WORD; + } else { + return SymbolType.BYTE; + } + default: + return SymbolType.VAR; + } + } + + private SymbolType inferType(SSARValue rValue) { + SymbolType type = SymbolType.VAR; + if (rValue instanceof Symbol) { + Symbol rSymbol = (Symbol) rValue; + type = rSymbol.getType(); + } else if (rValue instanceof SSAConstantInteger) { + SSAConstantInteger rInt = (SSAConstantInteger) rValue; + if (rInt.getNumber() < 256) { + type = SymbolType.BYTE; + } else { + type = SymbolType.WORD; + } + } else if (rValue instanceof SSAConstantString) { + type = SymbolType.STRING; + } else if (rValue instanceof SSAConstantBool) { + type = SymbolType.BOOLEAN; + } + return type; + } + +} diff --git a/src/dk/camelot64/kickc/ssa/SSABasicBlock.java b/src/dk/camelot64/kickc/ssa/SSABasicBlock.java index a575225e9..9e35ecd15 100644 --- a/src/dk/camelot64/kickc/ssa/SSABasicBlock.java +++ b/src/dk/camelot64/kickc/ssa/SSABasicBlock.java @@ -1,7 +1,25 @@ package dk.camelot64.kickc.ssa; -/** - * Created by jespergravgaard on 02/05/2017. - */ +import java.util.ArrayList; +import java.util.List; + +/** A sequence of SSA statements */ public class SSABasicBlock { + + List statements; + + public SSABasicBlock() { + this.statements = new ArrayList<>(); + } + + public void addStatement(SSAStatement statement) { + this.statements.add(statement); + } + + @Override + public String toString() { + return "SSABasicBlock{" + + "statements=" + statements + + '}'; + } } diff --git a/src/dk/camelot64/kickc/ssa/SSAConstantInteger.java b/src/dk/camelot64/kickc/ssa/SSAConstantInteger.java index 82a02f5fc..b45c90caa 100644 --- a/src/dk/camelot64/kickc/ssa/SSAConstantInteger.java +++ b/src/dk/camelot64/kickc/ssa/SSAConstantInteger.java @@ -11,6 +11,10 @@ public class SSAConstantInteger implements SSAConstant { this.number = number; } + public Integer getNumber() { + return number; + } + @Override public String toString() { return Integer.toString(number); diff --git a/src/dk/camelot64/kickc/ssa/SSAJumpLabel.java b/src/dk/camelot64/kickc/ssa/SSAJumpLabel.java new file mode 100644 index 000000000..2913fc646 --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SSAJumpLabel.java @@ -0,0 +1,16 @@ +package dk.camelot64.kickc.ssa; + +/** A label representing a target of a jump in SSA code */ +public class SSAJumpLabel { + + private String name; + + public SSAJumpLabel(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/dk/camelot64/kickc/ssa/SSAOperator.java b/src/dk/camelot64/kickc/ssa/SSAOperator.java index f93a9f941..c3a80eaac 100644 --- a/src/dk/camelot64/kickc/ssa/SSAOperator.java +++ b/src/dk/camelot64/kickc/ssa/SSAOperator.java @@ -9,6 +9,10 @@ public class SSAOperator { this.operator = operator; } + public String getOperator() { + return operator; + } + @Override public String toString() { return operator ; diff --git a/src/dk/camelot64/kickc/ssa/SSASequence.java b/src/dk/camelot64/kickc/ssa/SSASequence.java new file mode 100644 index 000000000..fe91bdd1a --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SSASequence.java @@ -0,0 +1,33 @@ +package dk.camelot64.kickc.ssa; + +import java.util.ArrayList; +import java.util.List; + +/** + * A sequence of SSA Statements + */ +public class SSASequence { + + List statements; + + public SSASequence() { + this.statements = new ArrayList<>(); + } + + public void addStatement(SSAStatement statement) { + this.statements.add(statement); + } + + @Override + public String toString() { + StringBuffer out = new StringBuffer(); + for (SSAStatement statement : statements) { + out.append(statement.toString()+"\n"); + } + return out.toString(); + } + + public List getStatements() { + return statements; + } +} diff --git a/src/dk/camelot64/kickc/ssa/SSAStatement.java b/src/dk/camelot64/kickc/ssa/SSAStatement.java index 0098c9464..633e34a8a 100644 --- a/src/dk/camelot64/kickc/ssa/SSAStatement.java +++ b/src/dk/camelot64/kickc/ssa/SSAStatement.java @@ -3,50 +3,8 @@ package dk.camelot64.kickc.ssa; /** * Single Static Assignment Form Statement. * Intermediate form used for compiler optimization. - *
- * Xi := Yj <op> Zk - *
- * lValue := rValue1 <operator> rValue2 */ -public class SSAStatement implements SSAFragment { +public interface SSAStatement extends SSAFragment { - private SSALValue lValue; - private SSARValue rValue1; - private SSAOperator operator; - private SSARValue rValue2; - public SSAStatement(SSALValue lValue, SSARValue rValue1, SSAOperator operator, SSARValue rValue2) { - this.lValue = lValue; - this.rValue1 = rValue1; - this.operator = operator; - this.rValue2 = rValue2; - } - - public SSAStatement(SSALValue lValue, SSAOperator operator, SSARValue rValue2) { - this.lValue = lValue; - this.rValue1 = null; - this.operator = operator; - this.rValue2 = rValue2; - } - - public SSALValue getlValue() { - return lValue; - } - - public SSARValue getrValue1() { - return rValue1; - } - - public SSAOperator getOperator() { - return operator; - } - - public SSARValue getrValue2() { - return rValue2; - } - - @Override - public String toString() { - return lValue + " := " + (rValue1==null?"":rValue1) + " " + operator + " " + rValue2 ; - } } diff --git a/src/dk/camelot64/kickc/ssa/SSAStatementAssignment.java b/src/dk/camelot64/kickc/ssa/SSAStatementAssignment.java new file mode 100644 index 000000000..9fbc0b78f --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SSAStatementAssignment.java @@ -0,0 +1,66 @@ +package dk.camelot64.kickc.ssa; + +/** + * Single Static Assignment Form Statement. + * Intermediate form used for compiler optimization. + *
+ * Xi := Yj <op> Zk + *
+ * lValue := rValue1 <operator> rValue2 + */ +public class SSAStatementAssignment implements SSAStatement { + + /** The variable being assigned a value by the statement. */ + private SSALValue lValue; + + private SSARValue rValue1; + private SSAOperator operator; + private SSARValue rValue2; + + public SSAStatementAssignment(SSALValue lValue, SSARValue rValue2) { + this.lValue = lValue; + this.rValue1 = null; + this.operator = null; + this.rValue2 = rValue2; + } + + public SSAStatementAssignment(SSALValue lValue, SSARValue rValue1, SSAOperator operator, SSARValue rValue2) { + this.lValue = lValue; + this.rValue1 = rValue1; + this.operator = operator; + this.rValue2 = rValue2; + } + + public SSAStatementAssignment(SSALValue lValue, SSAOperator operator, SSARValue rValue2) { + this.lValue = lValue; + this.rValue1 = null; + this.operator = operator; + this.rValue2 = rValue2; + } + + public SSALValue getlValue() { + return lValue; + } + + public SSARValue getRValue1() { + return rValue1; + } + + public SSAOperator getOperator() { + return operator; + } + + public SSARValue getRValue2() { + return rValue2; + } + + @Override + public String toString() { + return + " "+ + lValue + " ← " + + (rValue1==null?"":rValue1+" ") + + (operator==null?"":operator+" ") + + rValue2 ; + } +} diff --git a/src/dk/camelot64/kickc/ssa/SSAStatementConditionalJump.java b/src/dk/camelot64/kickc/ssa/SSAStatementConditionalJump.java new file mode 100644 index 000000000..5b0726c09 --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SSAStatementConditionalJump.java @@ -0,0 +1,31 @@ +package dk.camelot64.kickc.ssa; + +/** + * Single Static Assignment Form Statement with a conditional jump. + * Intermediate form used for compiler optimization. + *
+ * if ( Yj ) goto XX + */ +public class SSAStatementConditionalJump implements SSAStatement { + + private SSARValue condition; + private SSAJumpLabel destination; + + public SSAStatementConditionalJump(SSARValue condition, SSAJumpLabel destination) { + this.condition = condition; + this.destination = destination; + } + + public SSARValue getCondition() { + return condition; + } + + public SSAJumpLabel getDestination() { + return destination; + } + + @Override + public String toString() { + return " "+"if("+condition+") goto "+destination; + } +} diff --git a/src/dk/camelot64/kickc/ssa/SSAStatementJump.java b/src/dk/camelot64/kickc/ssa/SSAStatementJump.java new file mode 100644 index 000000000..767406270 --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SSAStatementJump.java @@ -0,0 +1,25 @@ +package dk.camelot64.kickc.ssa; + +/** + * Single Static Assignment Form Statement unconditional jump. + * Intermediate form used for compiler optimization. + *
+ * goto XX + */ +public class SSAStatementJump implements SSAStatement { + + private SSAJumpLabel destination; + + public SSAStatementJump(SSAJumpLabel destination) { + this.destination = destination; + } + + public SSAJumpLabel getDestination() { + return destination; + } + + @Override + public String toString() { + return " "+"goto "+destination; + } +} diff --git a/src/dk/camelot64/kickc/ssa/SSAStatementJumpTarget.java b/src/dk/camelot64/kickc/ssa/SSAStatementJumpTarget.java new file mode 100644 index 000000000..4232b4bdb --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SSAStatementJumpTarget.java @@ -0,0 +1,24 @@ +package dk.camelot64.kickc.ssa; + +/** + * Single Static Assignment Form Statement Jump target. + */ +public class SSAStatementJumpTarget implements SSAStatement { + + private SSAJumpLabel label; + + public SSAStatementJumpTarget(SSAJumpLabel label) { + this.label = label; + } + + public SSAJumpLabel getLabel() { + return label; + } + + @Override + public String toString() { + return label+":"; + } + + +} diff --git a/src/dk/camelot64/kickc/ssa/SSAVariable.java b/src/dk/camelot64/kickc/ssa/SSAVariable.java index 6fad2458f..674832225 100644 --- a/src/dk/camelot64/kickc/ssa/SSAVariable.java +++ b/src/dk/camelot64/kickc/ssa/SSAVariable.java @@ -4,12 +4,21 @@ package dk.camelot64.kickc.ssa; *
    *
  • Each potential modification of a language variable becomes a separate versioned SSA variable.
  • *
  • Expressions are broken into separate SSA statements, each defining a new temporary/intermediate variable.
  • - *
*/ -public class SSAVariable implements SSARValue, SSALValue { + * + * + * Named variables are initially created without serials. These are first added after the basic control blocks have been defined. + * + * */ +public class SSAVariable implements SSARValue, SSALValue, SSAFragment { private String name; - private int serial; + private Integer serial; + + public SSAVariable(String name) { + this.name = name; + this.serial = null; + } public SSAVariable(String name, int serial) { this.name = name; @@ -26,6 +35,6 @@ public class SSAVariable implements SSARValue, SSALValue { @Override public String toString() { - return name + '_' + serial; + return name + (serial==null?"":"_"+serial); } } diff --git a/src/dk/camelot64/kickc/ssa/SSAVariableManager.java b/src/dk/camelot64/kickc/ssa/SSAVariableManager.java deleted file mode 100644 index ea62d1522..000000000 --- a/src/dk/camelot64/kickc/ssa/SSAVariableManager.java +++ /dev/null @@ -1,12 +0,0 @@ -package dk.camelot64.kickc.ssa; - -/** Manages creation of new variables from declarations or temporary (intermediate) */ -public class SSAVariableManager { - - private int nxtTemporaryId = 1; - - public SSAVariable generateIntermediateVariable() { - return new SSAVariable("@", nxtTemporaryId++); - } - -} diff --git a/src/dk/camelot64/kickc/ssa/Symbol.java b/src/dk/camelot64/kickc/ssa/Symbol.java new file mode 100644 index 000000000..cfa7991d2 --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/Symbol.java @@ -0,0 +1,43 @@ +package dk.camelot64.kickc.ssa; + +/** A Symbol (variable, jump label, etc.) */ +public class Symbol implements SSARValue, SSALValue, SSAFragment { + + private String name; + + private SymbolType type; + + private boolean intermediate; + + private boolean inferredType; + + public Symbol(String name, SymbolType type, boolean intermediate) { + this.name = name; + this.type = type; + this.intermediate = intermediate; + this.inferredType = false; + } + + public String getName() { + return name; + } + + public SymbolType getType() { + return type; + } + + public void setInferredType(SymbolType type) { + this.type = type; + this.inferredType = true; + } + + public boolean isIntermediate() { + return intermediate; + } + + @Override + public String toString() { + return "("+name + (intermediate?"*":"") + ": " + type.getTypeName() + (inferredType ?"*":"") + ")"; + } + +} diff --git a/src/dk/camelot64/kickc/ssa/SymbolManager.java b/src/dk/camelot64/kickc/ssa/SymbolManager.java new file mode 100644 index 000000000..656d9757a --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SymbolManager.java @@ -0,0 +1,68 @@ +package dk.camelot64.kickc.ssa; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Manages symbols (variables, labels) + */ +public class SymbolManager { + + private Map symbols; + + private int intermediateVarCount = 0; + private int intermediateLabelCount = 0; + + public SymbolManager() { + this.symbols = new LinkedHashMap<>(); + } + + private Symbol addSymbol(String name, SymbolType symbolType, boolean intermediate) { + if(symbols.get(name)!=null) { + throw new RuntimeException("Symbol already declared "+name); + } + Symbol symbol = new Symbol(name, symbolType, intermediate); + symbols.put(name, symbol); + return symbol; + } + + public void newVariableDeclaration(String name, String type) { + SymbolType symbolType = SymbolType.get(type); + addSymbol(name, symbolType, false); + } + + public Symbol newVariableAssignment(String varName) { + return symbols.get(varName); + } + + public Symbol newVariableUsage(String varName) { + return symbols.get(varName); + } + + public Symbol newIntermediateAssignment() { + String name = "$"+intermediateVarCount++; + Symbol symbol = addSymbol(name, SymbolType.VAR, true); + return symbol; + } + + public SSAJumpLabel newNamedJumpLabel(String name) { + Symbol symbol = addSymbol(name, SymbolType.LABEL, false); + return new SSAJumpLabel(name); + } + + public SSAJumpLabel newIntermediateJumpLabel() { + String name = "@"+ intermediateLabelCount++; + addSymbol(name, SymbolType.LABEL, true); + return new SSAJumpLabel(name); + } + + @Override + public String toString() { + StringBuffer out = new StringBuffer(); + for (String name : symbols.keySet()) { + Symbol symbol = symbols.get(name); + out.append(symbol.toString() + "\n"); + } + return out.toString(); + } +} diff --git a/src/dk/camelot64/kickc/ssa/SymbolType.java b/src/dk/camelot64/kickc/ssa/SymbolType.java new file mode 100644 index 000000000..cd7451243 --- /dev/null +++ b/src/dk/camelot64/kickc/ssa/SymbolType.java @@ -0,0 +1,33 @@ +package dk.camelot64.kickc.ssa; + +/** Symbol Types */ +public enum SymbolType { + BYTE("byte"), + WORD("word"), + STRING("string"), + BOOLEAN("boolean"), + LABEL("label"), + VAR("var"); + + private String typeName; + + SymbolType(String typeName) { + this.typeName = typeName; + } + + public String getTypeName() { + return typeName; + } + + public static SymbolType get(String name) { + switch (name) { + case "byte": return BYTE; + case "word": return WORD; + case "string": return STRING; + case "boolean": return BOOLEAN; + } + return null; + } + + +} diff --git a/src/dk/camelot64/kickc/test/main.java b/src/dk/camelot64/kickc/test/main.java index eff6b480d..9140a0000 100644 --- a/src/dk/camelot64/kickc/test/main.java +++ b/src/dk/camelot64/kickc/test/main.java @@ -3,7 +3,8 @@ package dk.camelot64.kickc.test; import dk.camelot64.kickc.parser.KickCLexer; import dk.camelot64.kickc.parser.KickCParser; import dk.camelot64.kickc.ssa.GenerateSSA; -import dk.camelot64.kickc.ssa.SSAVariableManager; +import dk.camelot64.kickc.ssa.PassTypeInference; +import dk.camelot64.kickc.ssa.SSASequence; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; @@ -18,9 +19,17 @@ public class main { KickCLexer lexer = new KickCLexer(input); KickCParser parser = new KickCParser(new CommonTokenStream(lexer)); parser.setBuildParseTree(true); - KickCParser.ExprContext expr = parser.expr(); - GenerateSSA ev = new GenerateSSA(new SSAVariableManager()); - Object result = ev.visit(expr); + KickCParser.FileContext file = parser.file(); + GenerateSSA ev = new GenerateSSA(); + ev.visit(file); + + PassTypeInference passTypeInference = new PassTypeInference(); + passTypeInference.inferTypes(ev.getSequence(), ev.getSymbols()); + + System.out.println("PROGRAM"); + System.out.println(ev.getSequence().toString()); + System.out.println("SYMBOLS"); + System.out.println(ev.getSymbols().toString()); } } diff --git a/src/dk/camelot64/kickc/test/test.kc b/src/dk/camelot64/kickc/test/test.kc index be3d6487d..2b83b3453 100644 --- a/src/dk/camelot64/kickc/test/test.kc +++ b/src/dk/camelot64/kickc/test/test.kc @@ -1 +1,7 @@ -1+2*3/(-$4+%101) = 12 || 1+1=2 && "qwe" < "asd" and not false \ No newline at end of file +byte a = 0; +word b = 0; +while(a<10) { + b=b+a; + a=a+1; +} +byte c = -a; \ No newline at end of file