#!/usr/bin/env python3 # code generated by "translate.py.pss" a pep script # bumble.sf.net/books/pars/ import sys, re # for sys.read(), write() and regex from unicodedata import category # for matching classes # may use, which could make the char class code easier # import regex # regex.findall(r'[[:graph:]]', 'a 0 a b z') class Machine: # make a new machine def __init__(self): self.size = 300 # how many elements in stack/tape/marks self.eof = False # end of stream reached? self.charsRead = 0 # how many chars already read self.linesRead = 1 # how many lines already read self.escape = "\\" self.delimiter = "*" # push/pop delimiter (default "*") self.counter = 0 # a counter for anything self.work = "" # the workspace self.stack = [] # stack for parse tokens self.cell = 0 # current tape cell self.tape = [""]*self.size # a list of attribute for tokens self.marks = [""]*self.size # marked tape cells # or dont initialse peep until "parse()" calls "setInput()" self.peep = sys.stdin.read(1) def setInput(self, newInput): print("to be implemented") # read one character from the input stream and # update the machine. def read(self): if self.eof: System.exit(0) self.charsRead += 1; # increment lines if self.peep == "\n": self.linesRead += 1 self.work += self.peep self.peep = sys.stdin.read(1) if not self.peep: self.eof = True # increment the tape pointer (command ++) and increase the # tape and marks array sizes if necessary def increment(self): self.cell += 1 if self.cell >= self.size: self.tape.append("") self.marks.append("") self.size += 1 # test if all chars in the text are in the unicode category # no! bug! because while checks mm.peep, but class test # checks mm.work. so have to adapt this function for either. def isInCategory(self, cat, text): for ch in text: if not category(ch).startswith(cat): return False return True # def # remove escape character: trivial method ? def unescapeChar(self, c): if len(self.work) > 0: self.work = self.work.replace("\\"+c, c) # add escape character : trivial def escapeChar(self, c): if len(self.work) > 0: self.work = self.work.replace(c, "\\"+c) # a helper function for the multiple escape char bug def countEscaped(self, suffix): count = 0 if self.work.endswith(suffix): # removesuffix not available in early python s = self.work.removesuffix(suffix) while s.endswith(self.escape): count += 1 s = s.removesuffix(self.escape) return count # reads the input stream until the workspace end with text def until(self, suffix): # read at least one character if self.eof: return self.read() while True: if self.eof: return # no. bug! count the trailing escape chars, odd=continue, even=stop if self.work.endswith(suffix): #and (not self.work.endswith(self.escape + suffix)): if self.countEscaped(suffix) % 2 == 0: return self.read() # pop the first token from the stack into the workspace */ def pop(self): if len(self.stack) == 0: return False self.work = mm.stack.pop() + self.work if self.cell > 0: self.cell -= 1 return True # push the first token from the workspace to the stack def push(self): # dont increment the tape pointer on an empty push if len(self.work) == 0: return False # need to get this from the delimiter. iFirst = self.work.find(self.delimiter); if iFirst == -1: self.stack.append(self.work) self.work = "" return True self.stack.append(self.work[0:iFirst+1]) self.work = self.work[iFirst+1:] self.increment() return True # this function is not used (the code is "inlined") def swap(self): s = self.work self.work = self.tape[self.cell] self.tape[self.cell] = s def goToMark(self, mark): markFound = False length = len(self.marks) for ii in range(length): if (mm.marks[ii] == mark): mm.cell = ii; markFound = True if (markFound == False): print("badmark '" + mark + "'!") exit() def writeToFile(self): f = open("sav.pp", "w") f.write(self.work) f.close() def printState(self): print("Stack[" + ",".join(self.stack) + "] Work[" + self.work + "] Peep[" + self.peep + "]"); print("Acc:" + str(self.counter) + " Esc:" + self.escape + " Delim:" + self.delimiter + " Chars:" + str(self.charsRead) + " Lines:" + str(self.linesRead) + " Cell:" + str(self.cell)); # this is where the actual parsing/compiling code should go # so that it can be used by other python classes/objects. Also # should have a stream argument. def parse(self, s): # a reset or "setinput()" method would be useful to parse a # different string/file/stream, without creating a new # machine object. # could use code like this to check if input is string or file if isinstance(s, file): print("") # self.reset(s) # self.reader = s elif isinstance(s, string): f = StringIO.StringIO("test") for line in f: print(line) else: f = sys.stdin sys.stdout.write("not implemented") # end of Machine class definition # will become: # mm.parse(sys.stdin) or # mm.parse("abcdef") or # open f; mm.parse(f) temp = "" mm = Machine() while (not mm.eof): # lex block while True: mm.read() # read # make character numbers (for error messages) relative # to line numbers if (mm.work == "\n"): mm.work = '' # clear mm.charsRead = 0 # nochars break if (re.match(r"^[\s]+$", mm.work)): mm.work = '' # clear break if (mm.work == "+" or mm.work == "-"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "opadd*" mm.push(); break if (mm.work == "*" or mm.work == "/"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "opmul*" mm.push(); break # modern pascal style comments, but not (* ... *) because # they are tricky to parse. if (mm.work == "{"): # save the line number for possible error message later mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "{" mm.until("}"); if (mm.work.endswith("}")): # can convert to another format mm.tape[mm.cell] = mm.work # put mm.work = '' # clear # create a "comment" parse token # comment-out this line to remove multiline comments from the # translated code # add "comment*"; push; break # make an unterminated multiline comment an error # to ease debugging of scripts. mm.work = '' # clear mm.work += "[pl/0 error] Unterminated pascal comment { ... } \n" mm.work += "stating at line number " mm.work += mm.tape[mm.cell] # get mm.work += "\n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "*" or mm.work == "/"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "opmul*" mm.push(); break # literal tokens # '!' is the print command in pl/0 # '?' is the read command in pl/0 # '#' means != # '.' marks the end of a program. if (mm.work == "." or mm.work == "," or mm.work == "=" or mm.work == ";" or mm.work == "(" or mm.work == ")"): mm.tape[mm.cell] = mm.work # put mm.work += "*" mm.push(); break if (mm.work == "!"): mm.work = '' # clear mm.work += "write" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "!*" mm.push(); break if (mm.work == "?"): mm.work = '' # clear mm.work += "read" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "?*" mm.push(); break # also need to parse <= >= comparison operators # '=' is comparison and also constant assignment. if (mm.work == "<" or mm.work == ">" or mm.work == "#"): # while while re.match(r"^[=]+$", mm.peep): if mm.eof: break mm.read() if (mm.work != "<" and mm.work != ">" and mm.work != ">=" and mm.work != "<=" and mm.work != "#"): # error, message and quit mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "[pl/0 error] unrecognised operator " mm.work += mm.tape[mm.cell] # get mm.work += " at line/char " mm.work += str(mm.linesRead) # lines mm.work += "/" mm.work += str(mm.charsRead) # chars mm.work += "\n" sys.stdout.write(mm.work) # print exit() if (mm.work == "#"): mm.work = '' # clear mm.work += "!=" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "compare*" mm.push(); if (mm.work == ":"): if (mm.eof): mm.work = '' # clear mm.work += "trailing : at end of file!\n" sys.stdout.write(mm.work) # print exit() mm.read() # read if (mm.work == ":="): mm.tape[mm.cell] = mm.work # put mm.work += "*" mm.push(); break mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "[pl/0 error] unrecognised operator " mm.work += mm.tape[mm.cell] # get mm.work += " at line/char " mm.work += str(mm.linesRead) # lines mm.work += "/" mm.work += str(mm.charsRead) # chars mm.work += "\n" sys.stdout.write(mm.work) # print exit() if (re.match(r"^[0-9]+$", mm.work)): # while while re.match(r"^[0-9]+$", mm.peep): if mm.eof: break mm.read() mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "number*" mm.push(); break if (mm.work.isalpha()): # while while mm.peep.isalpha(): if mm.eof: break mm.read() # make keywords case insensitive mm.tape[mm.cell] = mm.work # put mm.work = mm.work.lower() # lower # synonym with ! if (mm.work == "write" or mm.work == "writeln"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "!*" mm.push(); break # keywords in pl/0 if (mm.work == "const" or mm.work == "var" or mm.work == "if" or mm.work == "then" or mm.work == "while" or mm.work == "do" or mm.work == "begin" or mm.work == "end" or mm.work == "proc" or mm.work == "procedure" or mm.work == "call" or mm.work == "odd"): # or add ".key*" to remind us that these are keywords, # not parse tokens # add a space here for pretty printing later mm.tape[mm.cell] = mm.work # put if (mm.work == "procedure"): mm.work = '' # clear mm.work += "proc" mm.work += "*" mm.push(); break # restore non-lower case identifier mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "ident*" mm.push(); break if (mm.work != ""): # error unrecognised character mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] incorrect character '" mm.work += mm.tape[mm.cell] # get mm.work += "'\n" sys.stdout.write(mm.work) # print exit() break # parse block while True: # To visualise token reduction uncomment this below: mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " " sys.stdout.write(mm.work) # print mm.work = '' # clear mm.work += "\n" while (mm.pop()): continue # unstack sys.stdout.write(mm.work) # print # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip while (mm.push()): continue # stack # we will do these 5 token reductions first, so that # "statement*end*" does not have precedence mm.pop(); mm.pop(); mm.pop(); mm.pop(); mm.pop(); # sometimes statements are terminated by expressions, which # in turn must be terminated by something else, so there is a # trailing token there if (mm.work.startswith("if*condition*then*statement*") and mm.work != "if*condition*then*statement*"): # replace if len(mm.work) != 0: mm.work = mm.work.replace("if*condition*then*statement*", "statement*") mm.push(); mm.push(); if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += " " mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear # transfer 'invisible' token value mm.increment() # ++ mm.increment() # ++ mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ continue if (mm.work.startswith("while*condition*do*statement*") and mm.work != "while*condition*do*statement*"): # replace if len(mm.work) != 0: mm.work = mm.work.replace("while*condition*do*statement*", "statement*") mm.push(); mm.push(); if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += " " mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear # transfer invisible token value, and realign tape pointer mm.increment() # ++ mm.increment() # ++ mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ continue mm.push(); mm.push(); mm.push(); mm.push(); mm.push(); #----------------- # 1 token mm.pop(); # errors if (mm.eof and mm.work != ".*"): mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] Missing '.' at end of program ? \n" mm.work += " \n" sys.stdout.write(mm.work) # print exit() #----------------- # 2 tokens mm.pop(); # Some errors if (mm.work == "ident*ident*"): mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] 2 variable names in a row (is there a \n" mm.work += " missing operator?) \n" sys.stdout.write(mm.work) # print exit() if (mm.work == "vardec*const*"): mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] Constant declarations must precede variable \n" mm.work += " declarations in pl/0 \n" sys.stdout.write(mm.work) # print exit() if (mm.work == "condec*const*"): mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] only 1 constant declaration block is allowed \n" mm.work += " in each scope \n" sys.stdout.write(mm.work) # print exit() if (mm.work == "vardec*var*"): mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] only 1 variable declaration block is allowed \n" mm.work += " in each scope \n" sys.stdout.write(mm.work) # print exit() if (mm.work == ";*end*"): mm.work = '' # clear mm.work += str(mm.linesRead) # lines mm.work += ":" mm.work += str(mm.charsRead) # chars mm.work += " [pl/0 error] Last statement in block does not require \n" mm.work += " a semi-colon ';' \n" sys.stdout.write(mm.work) # print exit() # add an empty procset* (set of procedures) if there is # not one already. This simplifies program reduction later # it doesnt matter if there is 1 or 2 tokens here. if (mm.work.endswith("proc*") and not mm.work.startswith("procset*")): if (mm.work != "proc*"): # need to conserve the preceding token mm.push(); mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "procset*proc*" mm.push(); mm.push(); continue # only 1 token mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "procset*proc*" mm.push(); mm.push(); continue # procedure headers (name etc) if (mm.work == "procset*proceed*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "procset*" mm.push(); continue # "=" can be used for constant assignment but also as # a comparison operator if (mm.work == "=*ident*" or mm.work == "=*exp*"): # replace if len(mm.work) != 0: mm.work = mm.work.replace("=*", "compare*") mm.push(); mm.push(); continue if (mm.work == "exp*=*"): # replace if len(mm.work) != 0: mm.work = mm.work.replace("=*", "compare*") mm.push(); mm.push(); continue # expression transmog if (mm.work == "opmul*ident*" or mm.work == "opadd*ident*" or mm.work == "opmul*number*" or mm.work == "opadd*number*" or mm.work == "compare*ident*" or mm.work == "compare*number*" or mm.work == ":=*ident*" or mm.work == ":=*number*" or mm.work == "if*ident*" or mm.work == "if*number*" or mm.work == "while*ident*" or mm.work == "while*number*" or mm.work == "(*ident*" or mm.work == "(*number*" or mm.work == "!*ident*" or mm.work == "!*number*"): mm.push(); mm.work = '' # clear mm.work += "exp*" mm.push(); continue # expression transmutation if (mm.work == "ident*opmul*" or mm.work == "ident*opadd*" or mm.work == "number*opmul*" or mm.work == "number*opadd*" or mm.work == "ident*compare*" or mm.work == "number*compare*"): # replace if len(mm.work) != 0: mm.work = mm.work.replace("ident*", "exp*") # replace if len(mm.work) != 0: mm.work = mm.work.replace("number*", "exp*") mm.push(); mm.push(); continue if (mm.work == "const*conlist*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "condec*" mm.push(); continue # non-tail reduction for variables if (mm.work == "var*ident*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "varlist*" mm.push(); continue # variable decs if (mm.work == "varlist*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "vardec*" mm.push(); continue if (mm.work == "block*.*"): mm.work = '' # clear mm.work += "program*" mm.push(); continue if (mm.work == "call*ident*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); continue if (mm.work == "?*ident*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); continue # a multi statement block, between begin/end if (mm.work == "begin*statementset*"): # ident statements, mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n ") mm.work += "\nend" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); continue # tail reduction for statementsets if (mm.work == "statement*end*"): mm.work = '' # clear #get; ++; get; --; put; clear; mm.work += "statementset*" mm.push(); continue #----------------- # 3 tokens mm.pop(); # ! expression must be parsed while looked at the # trailing token, like all expression parsing if (mm.work.startswith("!*exp*") and mm.work != "!*exp*" and not mm.work.endswith("opmul*") and not mm.work.endswith("opadd*")): # need to conserve the "invisible" last token # replace if len(mm.work) != 0: mm.work = mm.work.replace("!*exp*", "statement*") mm.push(); mm.push(); # also transfer attributes if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ continue # procedure headers (name etc) if (mm.work == "proc*ident*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "prochead*" mm.push(); continue # procedure headers (name etc) if (mm.work == "prochead*statement*;*"): # indent the statement if it is not a begin/end construct mm.work = '' # clear mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if (not mm.work.startswith("begin")): mm.work = '' # clear mm.work += " " mm.work += mm.tape[mm.cell] # get # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n ") mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "proceed*" mm.push(); continue # expressions, this could be the trickiest aspect of # the grammar. transmog ident/number to exp if (mm.work == "exp*opmul*exp*" or mm.work == "exp*opadd*exp*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "exp*" mm.push(); continue if (mm.work == "(*exp*)*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "exp*" mm.push(); continue # this is reverse reduction of statements, which can be # useful since exp* requires a trailing token in order to # resolve. if (mm.work == "statement*;*statementset*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += ";\n" mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statementset*" mm.push(); continue # variable decs if (mm.work == "varlist*,*ident*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "varlist*" mm.push(); continue #----------------- # 4 tokens mm.pop(); # procedure headers (name etc). Need to indent the variable decs etc if (mm.work == "prochead*vardec*statement*;*" or mm.work == "prochead*condec*statement*;*"): # indent the variable/constant declaration mm.work = '' # clear mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n ") mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "proceed*" mm.push(); continue # ident and number have already been transmog'ed into exp* # and =* into compare* if (mm.work.startswith("exp*compare*exp*") and mm.work != "exp*compare*exp*" and not mm.work.endswith("opmul*") and not mm.work.endswith("opadd*")): # need to conserve the "invisible" last token # replace if len(mm.work) != 0: mm.work = mm.work.replace("exp*compare*exp*", "condition*") mm.push(); mm.push(); if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear # transfer trailing token value mm.increment() # ++ mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ mm.work = '' # clear continue # also see the 5 token reduction, because of the trailing token # required by exp* if (mm.work == "if*condition*then*statement*" or mm.work == "while*condition*do*statement*"): # indent the statement if it is not a begin/end construct mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if (not mm.work.startswith("begin")): mm.work = '' # clear mm.work += " " mm.work += mm.tape[mm.cell] # get # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n ") mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); continue # lookahead for expressions in statements # the problem is: x:=4*3+1 will be parsed at # statement*+1 if no lookahead. # If the expression # is not followed by a */+- then it is a complete statement # and can be reduced. lets transmog ident and number to make simpler if (mm.work.startswith("ident*:=*exp*") and mm.work != "ident*:=*exp*" and not mm.work.endswith("opmul*") and not mm.work.endswith("opadd*")): # need to conserve the "invisible" last token # replace if len(mm.work) != 0: mm.work = mm.work.replace("ident*:=*exp*", "statement*") mm.push(); mm.push(); if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ continue # tail reduction for constant decs if (mm.work == "ident*=*number*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "conlist*" mm.push(); continue # if (mm.work == "ident*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "varlist*" mm.push(); continue #----------------- # 5 tokens mm.pop(); # procedure headers (name etc), need to indent condec vardec if (mm.work == "prochead*condec*vardec*statement*;*"): # indent the variable and constant declarations mm.work = '' # clear mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n ") mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n ") mm.tape[mm.cell] = mm.work # put if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "proceed*" mm.push(); continue # constant declarations, tail reduction, but tail redux not # necessary if (mm.work == "ident*=*number*,*conlist*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "conlist*" mm.push(); continue # program reduction if (mm.eof): if (mm.work == "statement*.*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" if (mm.work == "vardec*statement*.*" or mm.work == "condec*statement*.*" or mm.work == "procset*statement*.*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n{ main program }\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" if (mm.work == "condec*vardec*statement*.*" or mm.work == "vardec*procset*statement*.*" or mm.work == "condec*procset*statement*.*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n{ main program }\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" if (mm.work == "condec*vardec*procset*statement*.*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += "\n{ main program }\n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" if (mm.eof): while (mm.pop()): continue # unstack if (mm.work == "program*"): mm.work = '' # clear mm.work += "{ ok pl/0 }\n" mm.work += "{ code checked and formatted by eg/plzero.pss }\n" mm.work += mm.tape[mm.cell] # get mm.work += "\n" sys.stdout.write(mm.work) # print exit() mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "Pl/0 program did not parse well \n" mm.work += "The final parse tokens were: " mm.work += mm.tape[mm.cell] # get mm.work += "\n" sys.stdout.write(mm.work) # print exit() mm.push(); mm.push(); mm.push(); mm.push(); mm.push(); break # parse # end of code generated by tr/translate.py.pss