diff --git a/compiler/keywords.py b/compiler/constants.py similarity index 95% rename from compiler/keywords.py rename to compiler/constants.py index f4c9511..a67c81f 100644 --- a/compiler/keywords.py +++ b/compiler/constants.py @@ -1,4 +1,4 @@ -from enum import IntFlag,auto +from enum import IntFlag,auto,Enum class PrintableFlag(IntFlag): def __repr__(self): @@ -106,3 +106,9 @@ class Token(PrintableFlag): STRINGCONSTANT = Atom.STRINGCONSTANT.value SYMBOL = auto() KEYWORD = auto() + +class SymbolType(Enum): + STATIC = auto() + FIELD = auto() + ARG = auto() + VAR = auto() \ No newline at end of file diff --git a/compiler/engine.py b/compiler/engine.py index 5eb3e03..1328610 100644 --- a/compiler/engine.py +++ b/compiler/engine.py @@ -1,5 +1,5 @@ from tokenizer import JackTokenizer -from keywords import * +from constants import * from grammar import * import sys diff --git a/compiler/grammar.py b/compiler/grammar.py index f1e1f18..ba18368 100644 --- a/compiler/grammar.py +++ b/compiler/grammar.py @@ -1,4 +1,4 @@ -from keywords import Atom +from constants import Atom """ The grammar is defined by the following constructs: diff --git a/compiler/__init__.py b/compiler/main.py similarity index 72% rename from compiler/__init__.py rename to compiler/main.py index 975db70..1f00d62 100644 --- a/compiler/__init__.py +++ b/compiler/main.py @@ -2,12 +2,11 @@ from engine import Engine import sys from pathlib import Path -if __name__ == '__main__': +if __name__ == '__main__' and len(sys.argv) > 1: p = Path(sys.argv[1]) if p.is_dir(): for f in p.glob("*.jack"): print("compiling %s" % f) Engine(f.as_posix()).compileClass() elif p.is_file(): - Engine(p.as_posix()).compileClass() - + Engine(p.as_posix()).compileClass() \ No newline at end of file diff --git a/compiler/symboltable.py b/compiler/symboltable.py new file mode 100644 index 0000000..f417231 --- /dev/null +++ b/compiler/symboltable.py @@ -0,0 +1,48 @@ +from constants import SymbolType + +class SymbolTable: + def __init__(self): + self.subroutineTable = {} + self.classTable = {} + self.subroutineIndex = 0 + self.classIndex = 0 + + def startSubroutine(self): + self.subroutineTable = {} + + def define(self, name, var_type, kind): + if (kind in [SymbolType.STATIC, SymbolType.FIELD]): + self.classTable[name] = (var_type, kind, self.classIndex) + self.classIndex += 1 + elif (kind in [SymbolType.ARG, SymbolType.VAR]): + self.subroutineTable[name] = (var_type, kind, self.subroutineIndex) + self.subroutineIndex += 1 + else: + raise Exception("Invalid SymbolType") + + def varCount(self, kind): + t = None + if (kind in [SymbolType.STATIC, SymbolType.FIELD]): + t = self.classTable + elif (kind in [SymbolType.ARG, SymbolType.VAR]): + t = self.subroutineTable + else: + raise Exception("Invalid SymbolType") + return len([i for i in t.values() if i[1] == kind]) + + def _lookup(self, name, index): + if name in self.classTable: + return self.classTable[name][index] + elif name in self.subroutineTable: + return self.subroutineTable[name][index] + else: + raise Exception("Invalid variable name") + + def TypeOf(self, name): + return self._lookup(name, 0) + + def KindOf(self, name): + return self._lookup(name, 1) + + def IndexOf(self, name): + return self._lookup(name, 2) diff --git a/compiler/symboltable_test.py b/compiler/symboltable_test.py new file mode 100644 index 0000000..7a92009 --- /dev/null +++ b/compiler/symboltable_test.py @@ -0,0 +1,53 @@ +from symboltable import SymbolTable +from constants import SymbolType +def test_st_init(): + st = SymbolTable() + assert(st.subroutineTable == {}) + assert(st.classTable == {}) + +def test_st_define(): + st = SymbolTable() + st.define("first", "int", SymbolType.STATIC) + st.define("second", "SomeClass", SymbolType.FIELD) + st.define("third", "String", SymbolType.ARG) + st.define("fourth", "bool", SymbolType.VAR) + + assert(st.classTable == { + "first": ("int", SymbolType.STATIC, 0), + "second": ("SomeClass", SymbolType.FIELD, 1), + }) + + assert(st.subroutineTable == { + "third": ("String", SymbolType.ARG, 0), + "fourth": ("bool", SymbolType.VAR, 1), + }) + +def test_subroutine(): + st = SymbolTable() + st.define("first", "int", SymbolType.ARG) + st.startSubroutine() + assert(st.subroutineTable == {}) + +def test_var_count(): + st = SymbolTable() + st.define("first", "int", SymbolType.STATIC) + st.define("second", "SomeClass", SymbolType.FIELD) + st.define("third", "String", SymbolType.ARG) + st.define("fourth", "bool", SymbolType.VAR) + + assert(st.varCount(SymbolType.STATIC) == 1) + assert(st.varCount(SymbolType.FIELD) == 1) + assert(st.varCount(SymbolType.ARG) == 1) + assert(st.varCount(SymbolType.VAR) == 1) + +def test_lookups(): + st = SymbolTable() + st.define("first", "int", SymbolType.STATIC) + st.define("second", "SomeClass", SymbolType.FIELD) + st.define("third", "String", SymbolType.ARG) + st.define("fourth", "bool", SymbolType.VAR) + + assert(st.KindOf("first") == SymbolType.STATIC) + assert(st.TypeOf("second") == "SomeClass") + assert(st.IndexOf("third") == 0) + assert(st.IndexOf("fourth") == 1) \ No newline at end of file diff --git a/compiler/tokenizer.py b/compiler/tokenizer.py index 076d406..7d20110 100644 --- a/compiler/tokenizer.py +++ b/compiler/tokenizer.py @@ -1,5 +1,5 @@ import re -from keywords import * +from constants import * from html import escape from enum import Enum # Superclass in some sense