Initial work on a Symbol Table abstraction
This commit is contained in:
parent
66efa72230
commit
3b541898e2
|
@ -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()
|
|
@ -1,5 +1,5 @@
|
|||
from tokenizer import JackTokenizer
|
||||
from keywords import *
|
||||
from constants import *
|
||||
from grammar import *
|
||||
import sys
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from keywords import Atom
|
||||
from constants import Atom
|
||||
|
||||
"""
|
||||
The grammar is defined by the following constructs:
|
||||
|
|
|
@ -2,7 +2,7 @@ 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"):
|
||||
|
@ -10,4 +10,3 @@ if __name__ == '__main__':
|
|||
Engine(f.as_posix()).compileClass()
|
||||
elif p.is_file():
|
||||
Engine(p.as_posix()).compileClass()
|
||||
|
|
@ -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)
|
|
@ -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)
|
|
@ -1,5 +1,5 @@
|
|||
import re
|
||||
from keywords import *
|
||||
from constants import *
|
||||
from html import escape
|
||||
from enum import Enum
|
||||
# Superclass in some sense
|
||||
|
|
Loading…
Reference in New Issue