added functions
This commit is contained in:
		
							parent
							
								
									eaf492d1c1
								
							
						
					
					
						commit
						85e5f569b4
					
				| 
						 | 
				
			
			@ -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<Reg> registers;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Maps nodes to {@link SimpleType}s.
 | 
			
		||||
	 * Maps nodes to {@link Type}s.
 | 
			
		||||
	 */
 | 
			
		||||
	public ParseTreeProperty<SimpleType> types;
 | 
			
		||||
	public ParseTreeProperty<Type> types;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Maps nodes to {@link Variable}s.
 | 
			
		||||
	 */
 | 
			
		||||
	public ParseTreeProperty<Variable<SimpleType>> variables;
 | 
			
		||||
	public ParseTreeProperty<Variable<Type>> variables;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Maps nodes to their function scope.
 | 
			
		||||
	 */
 | 
			
		||||
	public ParseTreeProperty<Variable<Type>> function;
 | 
			
		||||
	public Stack<Variable<Type>> 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<>();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
    | <assoc=right> variable ASSIGN singleExpr #assign
 | 
			
		||||
    | variable #var
 | 
			
		||||
    | LITERAL10 #number
 | 
			
		||||
| 
						 | 
				
			
			@ -60,6 +62,7 @@ AND: '&&';
 | 
			
		|||
OR: '||';
 | 
			
		||||
 | 
			
		||||
DECLARE: 'var';
 | 
			
		||||
FUNCTION: 'function';
 | 
			
		||||
INTTYPE: 'int';
 | 
			
		||||
BOOLTYPE: 'bool';
 | 
			
		||||
CHARTYPE: 'char';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,6 +102,13 @@ public class BasicBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
 | 
			
		|||
	 * {@link #visitChildren} on {@code ctx}.</p>
 | 
			
		||||
	 */
 | 
			
		||||
	@Override public T visitInfix5(BasicParser.Infix5Context ctx) { return visitChildren(ctx); }
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@inheritDoc}
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The default implementation returns the result of calling
 | 
			
		||||
	 * {@link #visitChildren} on {@code ctx}.</p>
 | 
			
		||||
	 */
 | 
			
		||||
	@Override public T visitCall(BasicParser.CallContext ctx) { return visitChildren(ctx); }
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@inheritDoc}
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +116,13 @@ public class BasicBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements
 | 
			
		|||
	 * {@link #visitChildren} on {@code ctx}.</p>
 | 
			
		||||
	 */
 | 
			
		||||
	@Override public T visitNumber(BasicParser.NumberContext ctx) { return visitChildren(ctx); }
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@inheritDoc}
 | 
			
		||||
	 *
 | 
			
		||||
	 * <p>The default implementation returns the result of calling
 | 
			
		||||
	 * {@link #visitChildren} on {@code ctx}.</p>
 | 
			
		||||
	 */
 | 
			
		||||
	@Override public T visitFuncDeclare(BasicParser.FuncDeclareContext ctx) { return visitChildren(ctx); }
 | 
			
		||||
	/**
 | 
			
		||||
	 * {@inheritDoc}
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<ExprContext> 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<TerminalNode> LISTDELIM() { return getTokens(BasicParser.LISTDELIM); }
 | 
			
		||||
		public TerminalNode LISTDELIM(int i) {
 | 
			
		||||
			return getToken(BasicParser.LISTDELIM, i);
 | 
			
		||||
		}
 | 
			
		||||
		public CallContext(SingleExprContext ctx) { copyFrom(ctx); }
 | 
			
		||||
		@Override
 | 
			
		||||
		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 | 
			
		||||
			if ( visitor instanceof BasicVisitor ) return ((BasicVisitor<? extends T>)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<TypeContext> type() {
 | 
			
		||||
			return getRuleContexts(TypeContext.class);
 | 
			
		||||
		}
 | 
			
		||||
		public TypeContext type(int i) {
 | 
			
		||||
			return getRuleContext(TypeContext.class,i);
 | 
			
		||||
		}
 | 
			
		||||
		public List<TerminalNode> 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<TerminalNode> LISTDELIM() { return getTokens(BasicParser.LISTDELIM); }
 | 
			
		||||
		public TerminalNode LISTDELIM(int i) {
 | 
			
		||||
			return getToken(BasicParser.LISTDELIM, i);
 | 
			
		||||
		}
 | 
			
		||||
		public FuncDeclareContext(SingleExprContext ctx) { copyFrom(ctx); }
 | 
			
		||||
		@Override
 | 
			
		||||
		public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 | 
			
		||||
			if ( visitor instanceof BasicVisitor ) return ((BasicVisitor<? extends T>)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<A\5\4\3\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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,6 +99,13 @@ public interface BasicVisitor<T> extends ParseTreeVisitor<T> {
 | 
			
		|||
	 * @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<T> extends ParseTreeVisitor<T> {
 | 
			
		|||
	 * @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}.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<SimpleType> {
 | 
			
		||||
	private CachingSymbolTable<SimpleType> symbols;
 | 
			
		||||
public class BoppiBasicChecker extends BasicBaseVisitor<Type> {
 | 
			
		||||
	private CachingSymbolTable<Type> symbols;
 | 
			
		||||
	private Annotations an;
 | 
			
		||||
	private Logger log;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,37 +37,59 @@ public class BoppiBasicChecker extends BasicBaseVisitor<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public SimpleType visitDeclare(DeclareContext ctx) {
 | 
			
		||||
	public Type visitDeclare(DeclareContext ctx) {
 | 
			
		||||
		try {
 | 
			
		||||
			Variable<SimpleType> var = symbols.put(ctx.IDENTIFIER().getText(), visit(ctx.type()));
 | 
			
		||||
			Variable<Type> 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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public SimpleType visitIf(IfContext ctx) {
 | 
			
		||||
	public Type visitFuncDeclare(FuncDeclareContext ctx) {
 | 
			
		||||
		try {
 | 
			
		||||
			List<Type> parameterTypes = ctx.type().stream().skip(1).map(this::visit).collect(Collectors.toList());
 | 
			
		||||
			FunctionType type = new FunctionType(visit(ctx.result), parameterTypes, symbols.functionDepth);
 | 
			
		||||
			Variable<Type> 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<Type> 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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<Type>(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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> var = symbols.get(ctx.getText());
 | 
			
		||||
			Variable<Type> 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<SimpleType> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@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<SimpleType> {
 | 
			
		|||
	 * @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()));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<Void> {
 | 
			
		||||
	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<Void> {
 | 
			
		|||
		an = annotations;
 | 
			
		||||
		prog = new Program();
 | 
			
		||||
		regNum = 0;
 | 
			
		||||
 | 
			
		||||
		emit(OpCode.loadI, new Num(0), zero);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -82,12 +82,25 @@ public class BoppiBasicGenerator extends BasicBaseVisitor<Void> {
 | 
			
		|||
		return reg;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private <T> Reg getVar(ParserRuleContext node, Variable<T> 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<Void> {
 | 
			
		|||
	 * 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<Void> {
 | 
			
		|||
		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<Type> 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<Void> {
 | 
			
		|||
 | 
			
		||||
		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<Void> {
 | 
			
		|||
	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<Void> {
 | 
			
		|||
 | 
			
		||||
		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<Void> {
 | 
			
		|||
		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<Void> {
 | 
			
		|||
	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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,11 +13,14 @@ import java.util.function.Supplier;
 | 
			
		|||
 * @param <T>
 | 
			
		||||
 *            the typing class
 | 
			
		||||
 */
 | 
			
		||||
public class CachingSymbolTable<T> {
 | 
			
		||||
public class CachingSymbolTable<T extends Type> {
 | 
			
		||||
	protected Stack<Map<String, Variable<T>>> symbolMapStack;
 | 
			
		||||
	protected Stack<Integer> offsets;
 | 
			
		||||
	protected Stack<Integer> functionSizes;
 | 
			
		||||
	protected Map<String, Variable<T>> 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<T> {
 | 
			
		|||
		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<T> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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<T> {
 | 
			
		|||
		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 <U>
 | 
			
		||||
	 *            the type of the code's return value
 | 
			
		||||
| 
						 | 
				
			
			@ -74,10 +106,30 @@ public class CachingSymbolTable<T> {
 | 
			
		|||
		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<T> {
 | 
			
		|||
		if (symbolMapStack.peek().containsKey(id))
 | 
			
		||||
			throw new Exception(String.format("Identifier '%s' already declared in this scope.", id));
 | 
			
		||||
 | 
			
		||||
		Variable<T> var = new Variable<>(type, offset);
 | 
			
		||||
		// TODO refactor to get type size
 | 
			
		||||
		offset += ((SimpleType) type).getSize();
 | 
			
		||||
		Variable<T> 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<T> {
 | 
			
		|||
	 *            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<T> 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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
package pp.s1184725.boppi;
 | 
			
		||||
 | 
			
		||||
import java.util.EmptyStackException;
 | 
			
		||||
 | 
			
		||||
public class DebugCachingSymbolTable<T extends Type> extends CachingSymbolTable<T> {
 | 
			
		||||
 | 
			
		||||
	@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<T> 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<T> 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();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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<Type> parameters;
 | 
			
		||||
	private List<Integer> offsets;
 | 
			
		||||
	private Type result;
 | 
			
		||||
	private int localDataSize;
 | 
			
		||||
	private int depth;
 | 
			
		||||
 | 
			
		||||
	public FunctionType(Type returnType, List<Type> 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<Type> getParameters() {
 | 
			
		||||
		return parameters;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setParameters(List<Type> parameters) {
 | 
			
		||||
		this.parameters = parameters;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public List<Integer> getOffsets() {
 | 
			
		||||
		return offsets;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public int getDepth() {
 | 
			
		||||
		return depth;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setDepth(int newDepth) {
 | 
			
		||||
		depth = newDepth;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,16 +13,12 @@ import pp.iloc.eval.Machine;
 | 
			
		|||
 * <li>void (empty/unit type)</li>
 | 
			
		||||
 * </ul>
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()) + "<br/>");
 | 
			
		||||
				if (annotater.types.get(ctx) != null)
 | 
			
		||||
					sb.append("type: " + escape(annotater.types.get(ctx).name()) + "<br/>");
 | 
			
		||||
					sb.append("type: " + escape(annotater.types.get(ctx).toString()) + "<br/>");
 | 
			
		||||
				sb.append(">;style=filled;fillcolor=\"" + hue + "+0.1+1\"]\n");
 | 
			
		||||
 | 
			
		||||
				if (ctx.children != null)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ package pp.s1184725.boppi;
 | 
			
		|||
 */
 | 
			
		||||
public class Variable<T> {
 | 
			
		||||
	private final T type;
 | 
			
		||||
	private final int depth;
 | 
			
		||||
	private final int offset;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -19,8 +20,9 @@ public class Variable<T> {
 | 
			
		|||
	 * @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<T> {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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<T> {
 | 
			
		|||
		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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue