diff --git a/compiler/engine.py b/compiler/engine.py index 3595c4a..3b2a44c 100644 --- a/compiler/engine.py +++ b/compiler/engine.py @@ -77,9 +77,16 @@ class Engine: self.write(line, end="") self.advance() - for e in grammar: - self.compile(e) + print(lookup_keys) + print("grammar inside matchDict ") + print(grammar) + + # Grammar can be none + if grammar: + self.compile(grammar) + + # TODO: Improve open and close for dicts if isinstance(el, Element): self.close(el) @@ -109,7 +116,7 @@ class Engine: self.advance() return True else: - # print("%s != %s" % (current, expected)) + print("%s != %s" % (current, expected)) return False def open(self, el): @@ -124,29 +131,37 @@ class Engine: If you set matchOnly = true, the cursor will not move forward If it is forced to move forward (LL1 grammar for eg,) it will raise an error instead """ - def compile(self, thing, matchOnly = False): - if isinstance(thing, Element): - ret = self.compile(thing.grammar[0], True) - if (matchOnly == False and ret) or thing.empty: - self.open(thing) - for e in thing.grammar: - ret = self.compile(e) - self.close(thing) - return ret - elif callable(thing): - grammar = thing() - return self.compile(grammar, matchOnly) - else: - grammar = thing - grammarType = type(grammar) + def compile(self, grammar, matchOnly = False): + if callable(grammar): + ret = self.compile(grammar(), matchOnly) + elif isinstance(grammar, Element): + ret = self.compile(grammar.grammar, True) - if grammarType == list: - return self.ZeroOrMany(grammar, matchOnly) - elif grammarType == dict: - return self.MatchDict(grammar, matchOnly) - elif grammarType == tuple: - return self.ZeroOrOne(grammar, matchOnly) - elif grammarType == Atom: - return self.MatchAtom(grammar, matchOnly) + if grammar.name == 'term': + print(ret) + print(self.atom()) + + if (matchOnly == False and ret) or grammar.empty: + self.open(grammar) + # Avoid useless compilation + if ret: + ret = self.compile(grammar.grammar) + self.close(grammar) + elif isinstance(grammar, Sequence): + if matchOnly: + ret = self.compile(grammar[0], True) else: - raise Exception("Should not have reached here") + for e in grammar: + ret = self.compile(e) + elif isinstance(grammar, list): + ret = self.ZeroOrMany(grammar, matchOnly) + elif isinstance(grammar,dict): + ret = self.MatchDict(grammar, matchOnly) + elif isinstance(grammar,tuple): + ret = self.ZeroOrOne(grammar, matchOnly) + elif isinstance(grammar,Atom): + ret = self.MatchAtom(grammar, matchOnly) + else: + raise Exception("Invalid Grammar") + + return ret diff --git a/compiler/grammar.py b/compiler/grammar.py index c519f9a..f1e1f18 100644 --- a/compiler/grammar.py +++ b/compiler/grammar.py @@ -20,73 +20,109 @@ This is basically an attempt to translate Figure 10.5 from the book into a Python structure. """ + +class Sequence(list): + def first(self): + return self[0] + class Element: # Usually I avoid inverted boolean variable names, but this is much cleaner def __init__(self, name, grammar): - assert(type(grammar)==list) + # Since Any derives from list, this ought to work + assert(isinstance(grammar, list) or isinstance(grammar, dict)) self.name = name self.grammar = grammar self.empty = False + def first(self): + if isinstance(self.grammar, list): + return self.grammar[0] + elif isinstance(self.grammar, dict): + return list(self.grammar.keys())[0] + def __repr__(self): return self.name -CLASSVARDEC = Element('classVarDec', [ +CLASSVARDEC = Element('classVarDec', Sequence([ # static|field type (, name)* ; Atom.STATIC | Atom.FIELD, Atom.INT | Atom.CHAR | Atom.BOOLEAN | Atom.IDENTIFIER, Atom.IDENTIFIER, + # Zero or one of these [Atom.COMMA, Atom.IDENTIFIER], Atom.SEMICOLON -]) +])) -VARDEC = Element('varDec', [Atom.VAR, Atom.INT | Atom.CHAR | Atom.BOOLEAN | Atom.IDENTIFIER, Atom.IDENTIFIER, +VARDEC = Element('varDec', Sequence([ + Atom.VAR, Atom.INT | Atom.CHAR | Atom.BOOLEAN | Atom.IDENTIFIER, Atom.IDENTIFIER, + # Zero or one of these [Atom.COMMA, Atom.IDENTIFIER], Atom.SEMICOLON -]) +])) -# Since this is not a non-terminal, we can just write it as a constant +# Since these are not a non-terminal, we can just write it as a constant OP = Atom.PLUS | Atom.MINUS | Atom.MUL | Atom.DIV | Atom.AND | Atom.OR | Atom.GT | Atom.LT | Atom.EQ UNARY_OP = Atom.NOT | Atom.MINUS -CONSTANT = Atom.TRUE | Atom.FALSE|Atom.NULL|Atom.THIS +CONSTANT = Atom.TRUE | Atom.FALSE | Atom.NULL | Atom.THIS """ Pseudo-element to help define subroutine declarations """ -RETURN_TYPES= Atom.INT | Atom.CHAR|Atom.BOOLEAN|Atom.IDENTIFIER|Atom.VOID +RETURN_TYPES= Atom.INT | Atom.CHAR | Atom.BOOLEAN | Atom.IDENTIFIER | Atom.VOID -# TODO: This is missing the following: -# var [expression] -# subRoutineCall -# (expressions in parenthes) -# unaryOP TERM -TERM = Element('term', [ - Atom.INTEGERCONSTANT | Atom.STRINGCONSTANT | Atom.TRUE | Atom.FALSE | Atom.NULL| Atom.THIS | Atom.IDENTIFIER -]) +# This is a flattened version of the Term structure +TERM = Element('term', { + (Atom.INTEGERCONSTANT,): None, + (Atom.STRINGCONSTANT,): None, + (Atom.TRUE,): None, + (Atom.FALSE,): None, + (Atom.NULL,): None, + (Atom.THIS,): None, + # unaryOp TERM + (Atom.NOT,): Sequence([lambda: TERM]), + (Atom.MINUS,): Sequence([lambda: TERM]), + # (expression) + (Atom.PAREN_OPEN,): Sequence([lambda: EXPRESSION, Atom.PAREN_CLOSE]), + (Atom.IDENTIFIER,): { + # array lookup + (Atom.SQUARE_OPEN,): Sequence([lambda: EXPRESSION, Atom.SQUARE_CLOSE]), + # Subroutine call, but with class name + (Atom.DOT,): Sequence([ + Atom.IDENTIFIER, + Atom.PAREN_OPEN, + lambda: EXPRESSIONLIST, + Atom.PAREN_CLOSE + ]), + # Subroutine call, but to same class + (Atom.PAREN_OPEN,): Sequence([ + lambda: EXPRESSIONLIST, + Atom.PAREN_CLOSE + ]) + } +}) -EXPRESSION = Element('expression', [TERM, [OP, TERM]]) +EXPRESSION = Element('expression', Sequence([TERM, [OP, TERM]])) -EXPRESSIONLIST = Element('expressionList', [(EXPRESSION, [Atom.COMMA, EXPRESSION])]) +EXPRESSIONLIST = Element('expressionList', Sequence([ + (EXPRESSION, [Atom.COMMA, EXPRESSION]) +])) -DO_STATEMENT = Element('doStatement', [{ - (Atom.IDENTIFIER, Atom.PAREN_OPEN): [ - EXPRESSIONLIST, - Atom.PAREN_CLOSE, - ], - (Atom.IDENTIFIER, Atom.DOT): [ - Atom.IDENTIFIER, - Atom.PAREN_OPEN, - EXPRESSIONLIST, - Atom.PAREN_CLOSE - ] -},Atom.SEMICOLON]) +SUBROUTINE_CALL = [ + (Atom.IDENTIFIER, Atom.DOT), + Atom.IDENTIFIER, + Atom.PAREN_OPEN, + EXPRESSIONLIST, + Atom.PAREN_CLOSE +] -LET_STATEMENT = Element('letStatement', [ +DO_STATEMENT = Element('doStatement', Sequence([SUBROUTINE_CALL,Atom.SEMICOLON])) + +LET_STATEMENT = Element('letStatement', Sequence([ Atom.IDENTIFIER, (Atom.SQUARE_OPEN, EXPRESSION, Atom.SQUARE_CLOSE), Atom.EQ, EXPRESSION, Atom.SEMICOLON -]) +])) -IF_STATEMENT = Element('ifStatement', [ +IF_STATEMENT = Element('ifStatement', Sequence([ Atom.PAREN_OPEN, EXPRESSION, Atom.PAREN_CLOSE, @@ -95,18 +131,20 @@ IF_STATEMENT = Element('ifStatement', [ Atom.BRACE_CLOSE, # This is the tricky one ( Atom.ELSE, Atom.BRACE_OPEN, lambda:STATEMENTS, Atom.BRACE_CLOSE) -]) +])) -WHILE_STATEMENT = Element('whileStatement', [ +WHILE_STATEMENT = Element('whileStatement', Sequence([ Atom.PAREN_OPEN, EXPRESSION, Atom.PAREN_CLOSE, Atom.BRACE_OPEN, lambda: STATEMENTS, Atom.BRACE_CLOSE, -]) +])) -RETURN_STATEMENT = Element('returnStatement', [(EXPRESSION), Atom.SEMICOLON]) +RETURN_STATEMENT = Element('returnStatement', Sequence([ + (EXPRESSION), Atom.SEMICOLON +])) # Just a constant, since this isn't a non-terminal STATEMENT = { @@ -117,31 +155,32 @@ STATEMENT = { (Atom.RETURN,): RETURN_STATEMENT } -STATEMENTS = Element('statements', [[STATEMENT]]) +STATEMENTS = Element('statements', Sequence([[STATEMENT]])) -SUBROUTINE_BODY = Element('subroutineBody', [ +SUBROUTINE_BODY = Element('subroutineBody', Sequence([ # One or more variable declarations # `var type varName (, varName)* ;` Atom.BRACE_OPEN, [VARDEC], STATEMENTS, Atom.BRACE_CLOSE -]) +])) # Parameter List = # ( # (type varName) (, type varName)* # )? # we use tuples for zero OR one of a sequence -PARAMETER_LIST = Element('parameterList', [( +PARAMETER_LIST = Element('parameterList', Sequence([( Atom.INT | Atom.CHAR | Atom.BOOLEAN | Atom.IDENTIFIER, Atom.IDENTIFIER, + # Zero or one of the following: [Atom.COMMA, Atom.INT | Atom.CHAR|Atom.BOOLEAN|Atom.IDENTIFIER, Atom.IDENTIFIER] -)]) +)])) EXPRESSIONLIST.empty = PARAMETER_LIST.empty = True -SUBROUTINEDEC = Element('subroutineDec', [ +SUBROUTINEDEC = Element('subroutineDec', Sequence([ # (constructor | function | method) (void | type) subRoutineName '(' parameterList ')' # subroutineBody Atom.CONSTRUCTOR | Atom.FUNCTION | Atom.METHOD, @@ -151,13 +190,13 @@ SUBROUTINEDEC = Element('subroutineDec', [ PARAMETER_LIST, Atom.PAREN_CLOSE, SUBROUTINE_BODY, -]) +])) -CLASS = Element('class', [ +CLASS = Element('class', Sequence([ Atom.CLASS, Atom.IDENTIFIER, Atom.BRACE_OPEN, [CLASSVARDEC], [SUBROUTINEDEC], Atom.BRACE_CLOSE -]) +])) diff --git a/projects/10/ArrayTest/Main.jack.xml b/projects/10/ArrayTest/Main.jack.xml new file mode 100644 index 0000000..e37c6b4 --- /dev/null +++ b/projects/10/ArrayTest/Main.jack.xml @@ -0,0 +1,286 @@ + + class + Main + { + + function + void + main + ( + + + ) + + { + + var + Array + a + ; + + + var + int + length + ; + + + var + int + i + , + sum + ; + + + + let + length + = + + + Keyboard + . + readInt + ( + + + + HOW MANY NUMBERS? + + + + ) + + + ; + + + let + a + = + + + Array + . + new + ( + + + + length + + + + ) + + + ; + + + let + i + = + + + 0 + + + ; + + + while + ( + + + i + + < + + length + + + ) + { + + + let + a + [ + + + i + + + ] + = + + + Keyboard + . + readInt + ( + + + + ENTER THE NEXT NUMBER: + + + + ) + + + ; + + + let + i + = + + + i + + + + + 1 + + + ; + + + } + + + let + i + = + + + 0 + + + ; + + + let + sum + = + + + 0 + + + ; + + + while + ( + + + i + + < + + length + + + ) + { + + + let + sum + = + + + sum + + + + + a + [ + + + i + + + ] + + + ; + + + let + i + = + + + i + + + + + 1 + + + ; + + + } + + + do + Output + . + printString + ( + + + + THE AVERAGE IS: + + + + ) + ; + + + do + Output + . + printInt + ( + + + + sum + + / + + length + + + + ) + ; + + + do + Output + . + println + ( + + + ) + ; + + + return + ; + + + } + + + } + diff --git a/projects/10/Square/Main.jack.xml b/projects/10/Square/Main.jack.xml new file mode 100644 index 0000000..6f8b6dc --- /dev/null +++ b/projects/10/Square/Main.jack.xml @@ -0,0 +1,244 @@ + + class + Main + { + + static + boolean + test + ; + + + function + void + main + ( + + + ) + + { + + var + SquareGame + game + ; + + + + let + game + = + + + SquareGame + . + new + ( + + + ) + + + ; + + + do + game + . + run + ( + + + ) + ; + + + do + game + . + dispose + ( + + + ) + ; + + + return + ; + + + } + + + + function + void + test + ( + + + ) + + { + + var + int + i + , + j + ; + + + var + String + s + ; + + + var + Array + a + ; + + + + if + ( + + + false + + + ) + { + + + let + s + = + + + string constant + + + ; + + + let + s + = + + + null + + + ; + + + let + a + [ + + + 1 + + + ] + = + + + a + [ + + + 2 + + + ] + + + ; + + + } + else + { + + + let + i + = + + + i + + * + + ( + + + - + + j + + + + ) + + + ; + + + let + j + = + + + j + + / + + ( + + + - + + 2 + + + + ) + + + ; + + + let + i + = + + + i + + | + + j + + + ; + + + } + + + return + ; + + + } + + + } + diff --git a/projects/10/Square/Square.jack.xml b/projects/10/Square/Square.jack.xml new file mode 100644 index 0000000..4db1f16 --- /dev/null +++ b/projects/10/Square/Square.jack.xml @@ -0,0 +1,1211 @@ + + class + Square + { + + field + int + x + , + y + ; + + + field + int + size + ; + + + constructor + Square + new + ( + + int + Ax + , + int + Ay + , + int + Asize + + ) + + { + + + let + x + = + + + Ax + + + ; + + + let + y + = + + + Ay + + + ; + + + let + size + = + + + Asize + + + ; + + + do + draw + ( + + + ) + ; + + + return + + + this + + + ; + + + } + + + + method + void + dispose + ( + + + ) + + { + + + do + Memory + . + deAlloc + ( + + + + this + + + + ) + ; + + + return + ; + + + } + + + + method + void + draw + ( + + + ) + + { + + + do + Screen + . + setColor + ( + + + + true + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + y + + + , + + + x + + + + + size + + + , + + + y + + + + + size + + + + ) + ; + + + return + ; + + + } + + + + method + void + erase + ( + + + ) + + { + + + do + Screen + . + setColor + ( + + + + false + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + y + + + , + + + x + + + + + size + + + , + + + y + + + + + size + + + + ) + ; + + + return + ; + + + } + + + + method + void + incSize + ( + + + ) + + { + + + if + ( + + + ( + + + ( + + + y + + + + + size + + + ) + + < + + 254 + + + ) + + & + + ( + + + ( + + + x + + + + + size + + + ) + + < + + 510 + + + ) + + + ) + { + + + do + erase + ( + + + ) + ; + + + let + size + = + + + size + + + + + 2 + + + ; + + + do + draw + ( + + + ) + ; + + + } + + + return + ; + + + } + + + + method + void + decSize + ( + + + ) + + { + + + if + ( + + + size + + > + + 2 + + + ) + { + + + do + erase + ( + + + ) + ; + + + let + size + = + + + size + + - + + 2 + + + ; + + + do + draw + ( + + + ) + ; + + + } + + + return + ; + + + } + + + + method + void + moveUp + ( + + + ) + + { + + + if + ( + + + y + + > + + 1 + + + ) + { + + + do + Screen + . + setColor + ( + + + + false + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + ( + + + y + + + + + size + + + ) + + - + + 1 + + + , + + + x + + + + + size + + + , + + + y + + + + + size + + + + ) + ; + + + let + y + = + + + y + + - + + 2 + + + ; + + + do + Screen + . + setColor + ( + + + + true + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + y + + + , + + + x + + + + + size + + + , + + + y + + + + + 1 + + + + ) + ; + + + } + + + return + ; + + + } + + + + method + void + moveDown + ( + + + ) + + { + + + if + ( + + + ( + + + y + + + + + size + + + ) + + < + + 254 + + + ) + { + + + do + Screen + . + setColor + ( + + + + false + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + y + + + , + + + x + + + + + size + + + , + + + y + + + + + 1 + + + + ) + ; + + + let + y + = + + + y + + + + + 2 + + + ; + + + do + Screen + . + setColor + ( + + + + true + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + ( + + + y + + + + + size + + + ) + + - + + 1 + + + , + + + x + + + + + size + + + , + + + y + + + + + size + + + + ) + ; + + + } + + + return + ; + + + } + + + + method + void + moveLeft + ( + + + ) + + { + + + if + ( + + + x + + > + + 1 + + + ) + { + + + do + Screen + . + setColor + ( + + + + false + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + ( + + + x + + + + + size + + + ) + + - + + 1 + + + , + + + y + + + , + + + x + + + + + size + + + , + + + y + + + + + size + + + + ) + ; + + + let + x + = + + + x + + - + + 2 + + + ; + + + do + Screen + . + setColor + ( + + + + true + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + y + + + , + + + x + + + + + 1 + + + , + + + y + + + + + size + + + + ) + ; + + + } + + + return + ; + + + } + + + + method + void + moveRight + ( + + + ) + + { + + + if + ( + + + ( + + + x + + + + + size + + + ) + + < + + 510 + + + ) + { + + + do + Screen + . + setColor + ( + + + + false + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + x + + + , + + + y + + + , + + + x + + + + + 1 + + + , + + + y + + + + + size + + + + ) + ; + + + let + x + = + + + x + + + + + 2 + + + ; + + + do + Screen + . + setColor + ( + + + + true + + + + ) + ; + + + do + Screen + . + drawRectangle + ( + + + + ( + + + x + + + + + size + + + ) + + - + + 1 + + + , + + + y + + + , + + + x + + + + + size + + + , + + + y + + + + + size + + + + ) + ; + + + } + + + return + ; + + + } + + + } + diff --git a/projects/10/Square/SquareGame.jack.xml b/projects/10/Square/SquareGame.jack.xml new file mode 100644 index 0000000..6acbb6b --- /dev/null +++ b/projects/10/Square/SquareGame.jack.xml @@ -0,0 +1,643 @@ + + class + SquareGame + { + + field + Square + square + ; + + + field + int + direction + ; + + + constructor + SquareGame + new + ( + + + ) + + { + + + let + square + = + + + Square + . + new + ( + + + + 0 + + + , + + + 0 + + + , + + + 30 + + + + ) + + + ; + + + let + direction + = + + + 0 + + + ; + + + return + + + this + + + ; + + + } + + + + method + void + dispose + ( + + + ) + + { + + + do + square + . + dispose + ( + + + ) + ; + + + do + Memory + . + deAlloc + ( + + + + this + + + + ) + ; + + + return + ; + + + } + + + + method + void + moveSquare + ( + + + ) + + { + + + if + ( + + + direction + + = + + 1 + + + ) + { + + + do + square + . + moveUp + ( + + + ) + ; + + + } + + + if + ( + + + direction + + = + + 2 + + + ) + { + + + do + square + . + moveDown + ( + + + ) + ; + + + } + + + if + ( + + + direction + + = + + 3 + + + ) + { + + + do + square + . + moveLeft + ( + + + ) + ; + + + } + + + if + ( + + + direction + + = + + 4 + + + ) + { + + + do + square + . + moveRight + ( + + + ) + ; + + + } + + + do + Sys + . + wait + ( + + + + 5 + + + + ) + ; + + + return + ; + + + } + + + + method + void + run + ( + + + ) + + { + + var + char + key + ; + + + var + boolean + exit + ; + + + + let + exit + = + + + false + + + ; + + + while + ( + + + ~ + + exit + + + + ) + { + + + while + ( + + + key + + = + + 0 + + + ) + { + + + let + key + = + + + Keyboard + . + keyPressed + ( + + + ) + + + ; + + + do + moveSquare + ( + + + ) + ; + + + } + + + if + ( + + + key + + = + + 81 + + + ) + { + + + let + exit + = + + + true + + + ; + + + } + + + if + ( + + + key + + = + + 90 + + + ) + { + + + do + square + . + decSize + ( + + + ) + ; + + + } + + + if + ( + + + key + + = + + 88 + + + ) + { + + + do + square + . + incSize + ( + + + ) + ; + + + } + + + if + ( + + + key + + = + + 131 + + + ) + { + + + let + direction + = + + + 1 + + + ; + + + } + + + if + ( + + + key + + = + + 133 + + + ) + { + + + let + direction + = + + + 2 + + + ; + + + } + + + if + ( + + + key + + = + + 130 + + + ) + { + + + let + direction + = + + + 3 + + + ; + + + } + + + if + ( + + + key + + = + + 132 + + + ) + { + + + let + direction + = + + + 4 + + + ; + + + } + + + while + ( + + + ~ + + ( + + + key + + = + + 0 + + + ) + + + + ) + { + + + let + key + = + + + Keyboard + . + keyPressed + ( + + + ) + + + ; + + + do + moveSquare + ( + + + ) + ; + + + } + + + } + + + return + ; + + + } + + + } +