Skip to content

Instantly share code, notes, and snippets.

@Pigu-A
Created November 5, 2018 09:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pigu-A/a6b2997ab71504087fa5eb1cf953f28c to your computer and use it in GitHub Desktop.
Save Pigu-A/a6b2997ab71504087fa5eb1cf953f28c to your computer and use it in GitHub Desktop.
import argparse, string, sys
BCODES = {
"line": (10,),
"id": (11,),
"const": (12,),
"if": (13,0),
"goto": (14,),
"print": (15,0),
"stop": (16,0),
"+": (17,1),
"-": (17,2),
"<": (17,3),
"=": (17,4)
}
def scan(intx):
# Scans the Basic source and separate characters into a token list
toks = []
buf = ""
st = 0 # start at whitespace state
pos = 0
ttx = intx.lower() # make this case insensitive
while pos < len(ttx):
i = ttx[pos]
if st == 0: # whitespace
if i in string.digits: st = 1
elif i in string.ascii_letters: st = 2
elif i in string.punctuation: st = 3
else: pos += 1 # skip the current character
continue # skip the below lines
elif st == 1: # number digits
if i in string.digits:
buf += i # add the character to the buffer
pos += 1 # advance to the next character
continue
elif st == 2: # letters
if i in string.ascii_letters:
buf += i
pos += 1
continue
elif st == 3: # punctuations
if i in string.punctuation:
buf += i
pos += 1
continue
# different type of character found
toks.append((st,buf)) # add the current state and sequence to the list
buf = ""
st = 0 # set the state back to 0
if len(buf) > 0: toks.append((st,buf)) # empty the buffer
toks.append((-1,"EOF"))
return toks
# non-terminals are in integer index of parse table
# terminals are in string
PARSE_TABLE = [
[[["slnum"],[1,0]],[["EOF"],["EOF"]]], # pgm
[[["slnum"],["slnum",2]]], # line
[[["id"],[3]],[["if"],[7]],[["print"],[10]],[["goto"],[11]],[["stop"],["stop"]]], # stmt
[[["id"],["id","=",4]]], # asgmt
[[["id","+","-","const"],[6,5]]], # exp
[[["+"],["+",6]],[["-"],["-",6]],[["EOF","lnum"],[]]], # exp'
[[["id"],["id"]],[["const"],["const"]]], # term
[[["if"],["if",8,"gtdlnum"]]], # if
[[["id","const"],[6,9]]], # cond
[[["<"],["<",6]],[["="],["=",6]]], # cond'
[[["print"],["print","id"]]], # print
[[["goto"],["goto","lnum"]]], # goto
]
def validate(tok,term):
# Checks if the token type matches the terminal
# returns the B-Code if match, None if not
outb = None
if tok[0] == -1 and term == "EOF": outb = ()
if tok[0] == 1: # number
num = int(tok[1])
if term in ["lnum","slnum","gtdlnum"] and 1 <= num <= 1000:
outb = (num,)
if term == "slnum": outb = BCODES["line"]+outb
if term == "gtdlnum": outb = BCODES["goto"]+outb
if term == "const" and 0 <= num <= 100:
outb = BCODES[term]+(num,)
else: # letters and punctuations
if term in ["if","goto","print","stop","+","-","<","="] and tok[1] == term:
outb = BCODES[term]
elif term == "id" and tok[0] == 2 and len(tok[1]) == 1: # id
outb = BCODES["id"]+(ord(tok[1])-ord("a")+1,)
return outb
def parse(toks):
# Parses the loken list into a B-Code table
pstk = ["EOF",0] # parse stack
outb = []
tpos = 0 # token position
lpos = -1 # parsed line number
while tpos < len(toks):
ctok = toks[tpos]
if pstk[-1] == "EOF" and ctok == (-1,"EOF"):
break
elif type(pstk[-1]) is int: # non-terminal
found = False
for i in PARSE_TABLE[pstk[-1]]:
for j in i[0]: # valid terminals
found = validate(ctok,j) != None
if found:
pstk.pop()
break
if found:
pstk += i[1][::-1] # push the sequence to the stack backwards
break
if not found: raise Exception("Error in line {}".format(lpos))
else: # terminal
bcod = validate(ctok,pstk[-1])
if bcod == None: raise Exception("Error in line {}".format(lpos))
if pstk[-1] == "slnum": lpos = bcod[1]
outb += bcod
pstk.pop()
tpos += 1
return outb
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument('fi', metavar='in', type=argparse.FileType('r'), help='Input file name')
ap.add_argument('fo', metavar='out', type=argparse.FileType('w'), help='Output file name')
args = ap.parse_args()
toks = scan(args.fi.read())
bcodes = []
try:
bcodes = parse(toks)
except Exception as e:
print(e)
sys.exit()
args.fo.write(" ".join([str(i) for i in bcodes]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment