#!/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: not trivial see perl 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 #-------------- if (re.match(r"^[\s]+$", mm.work)): mm.work = '' # clear break #--------------- # We can ellide all these single character tests, because # the stack token is just the character itself with a * # Braces {} are used for blocks of commands, ',' and '.' for concatenating # tests with OR or AND logic. 'B' and 'E' for begin and end # tests, '!' is used for negation, ';' is used to terminate a # command. if (mm.work == "{" or mm.work == "}" or mm.work == ";" or mm.work == "," or mm.work == "." or mm.work == "!" or mm.work == "B" or mm.work == "E"): mm.tape[mm.cell] = mm.work # put mm.work += "*" mm.push(); break #--------------- # format: "text" if (mm.work == "\""): # save the start line number (for error messages) in case # there is no terminating quote character. mm.work = '' # clear mm.work += "line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ") " mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "\"" mm.until("\""); if (not mm.work.endswith("\"")): mm.work = '' # clear mm.work += "Unterminated quote character (\") starting at " 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 += "quote*" mm.push(); break #--------------- # format: 'text', single quotes are converted to double quotes # but we must escape embedded double quotes. if (mm.work == "'"): # save the start line number (for error messages) in case # there is no terminating quote character. mm.work = '' # clear mm.work += "line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ") " mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.until("'"); if (not mm.work.endswith("'")): mm.work = '' # clear mm.work += "Unterminated quote (') starting at " mm.work += mm.tape[mm.cell] # get mm.work += "!\n" sys.stdout.write(mm.work) # print exit() # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip mm.work = mm.work.replace("\"", mm.escape+"\"") mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "\"" mm.work += mm.tape[mm.cell] # get mm.work += "\"" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "quote*" mm.push(); break #--------------- # formats: [:space:] [a-z] [abcd] [:alpha:] etc # should class tests really be multiline??! if (mm.work == "["): # save the start line number (for error messages) in case # there is no terminating bracket character. mm.work = '' # clear mm.work += "line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ") " mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "[" mm.until("]"); if (mm.work == "[]"): mm.work = '' # clear mm.work += "pep script error at line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " empty character class [] \n" sys.stdout.write(mm.work) # print exit() if (not mm.work.endswith("]")): mm.work = '' # clear mm.work += "Unterminated class text ([...]) starting at " mm.work += mm.tape[mm.cell] # get mm.work += "" mm.work += "\n class text can be used in tests or with the 'while' and " mm.work += "\n 'whilenot' commands. For example: " mm.work += "\n [:alpha:] { while [:alpha:]; print; clear; }" mm.work += "\n " sys.stdout.write(mm.work) # print exit() # need to escape quotes so they dont interfere with the # quotes java needs for .matches("...") mm.work = mm.work.replace("\"", mm.escape+"\"") # the caret is not a negation operator in pep scripts # replace if len(mm.work) != 0: mm.work = mm.work.replace("^", "\\\\^") # save the class on the tape mm.tape[mm.cell] = mm.work # put # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop if (not mm.work.startswith("-")): # not a range class, eg [a-z] so need to escape '-' chars mm.work = '' # clear mm.work += mm.tape[mm.cell] # get # replace if len(mm.work) != 0: mm.work = mm.work.replace("-", "\\-") mm.tape[mm.cell] = mm.work # put if (mm.work.startswith("-")): # a range class, eg [a-z], check if it is correct # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip if (mm.work != "-"): mm.work = '' # clear mm.work += "Error in pep script at line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " Incorrect character range class " mm.work += mm.tape[mm.cell] # get mm.work += "" mm.work += "\n For example:" mm.work += "\n [a-g] # correct" mm.work += "\n [f-gh] # error! \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() mm.work = '' # clear mm.work += mm.tape[mm.cell] # get # restore class text if (mm.work.startswith("[:") and not mm.work.endswith(":]")): mm.work = '' # clear mm.work += "malformed character class starting at " mm.work += mm.tape[mm.cell] # get mm.work += "!\n" sys.stdout.write(mm.work) # print exit() if (mm.work.startswith("[:") and mm.work != "[:]"): # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop # unicode posix character classes # need unicodedata module # Also, abbreviations (not implemented in gh.c yet.) # this is tricky. For these types of classes we need a # function, not a regular expression. # this is a bit complicated, need to add mm.work or mm.peep # later because while check mm.peep but a class test # checks mm.work if (mm.work == "alnum" or mm.work == "N"): mm.work = '' # clear mm.work += "mm.work.isalnum()" if (mm.work == "alpha" or mm.work == "A"): mm.work = '' # clear mm.work += "mm.work.isalpha()" if (mm.work == "ascii" or mm.work == "I"): mm.work = '' # clear mm.work += "mm.work.isascii()" # py version 3.7 if (mm.work == "blank" or mm.work == "B"): mm.work = '' # clear mm.work += "[\\s]" if (mm.work == "cntrl" or mm.work == "C"): mm.work = '' # clear mm.work += "mm.isInCategory(\"C\", mm.work)" if (mm.work == "digit" or mm.work == "D"): mm.work = '' # clear mm.work += "[\\d]" # a hack, not true, bug if (mm.work == "graph" or mm.work == "G"): mm.work = '' # clear mm.work += "[\\S]" if (mm.work == "lower" or mm.work == "L"): mm.work = '' # clear mm.work += "mm.isInCategory(\"Ll\", mm.work)" if (mm.work == "print" or mm.work == "P"): mm.work = '' # clear mm.work += "[^\\w\\s]" if (mm.work == "punct" or mm.work == "T"): mm.work = '' # clear mm.work += "mm.isInCategory(\"P\", mm.work)" if (mm.work == "space" or mm.work == "S"): mm.work = '' # clear mm.work += "[\\s]" if (mm.work == "upper" or mm.work == "U"): mm.work = '' # clear mm.work += "mm.isInCategory(\"Lu\", mm.work)" if (mm.work == "xdigit" or mm.work == "X"): mm.work = '' # clear mm.work += "[0-9a-fA-F]" if (not mm.work.startswith("[") and not mm.work.startswith("mm.")): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "[error] Pep script syntax error near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += "Unknown character class [:" mm.work += mm.tape[mm.cell] # get mm.work += ":]\n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() mm.tape[mm.cell] = mm.work # put # special treatment for unicode category tests (no regex) if (mm.work.startswith("[")): mm.work = '' # clear mm.work += "\"^" mm.work += mm.tape[mm.cell] # get mm.work += "+$\"" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear # add quotes around the class and limits around the # class so it can be used with the string.matches() method # (must match the whole string, not just one character) mm.work += "class*" mm.push(); break #--------------- # formats: (eof) (EOF) (==) etc. if (mm.work == "("): mm.work = '' # clear mm.until(")"); # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip mm.tape[mm.cell] = mm.work # put if (mm.work == "eof" or mm.work == "EOF"): mm.work = '' # clear mm.work += "eof*" mm.push(); break if (mm.work == "=="): mm.work = '' # clear mm.work += "tapetest*" mm.push(); break mm.work += " << unknown test near line " mm.work += str(mm.linesRead) # lines mm.work += " of script.\n" mm.work += " bracket () tests are \n" mm.work += " (eof) test if end of stream reached. \n" mm.work += " (==) test if workspace is same as current tape cell \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() #--------------- # multiline and single line comments, eg #... and #* ... *# if (mm.work == "#"): mm.work = '' # clear mm.read() # read if (mm.work == "\n"): mm.work = '' # clear break # checking for multiline comments of the form "#* \n\n\n *#" # these are just ignored at the moment (deleted) 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.until("*#"); if (mm.work.endswith("*#")): # convert to python comments (#), python doesnt have multiline # comments, as far as I know # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\n#") 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 # compiled python # add "comment*"; push; break # make an unterminated multiline comment an error # to ease debugging of scripts. mm.work = '' # clear mm.work += "unterminated multiline 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() # single line comments. some will get lost. mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "#" mm.work += mm.tape[mm.cell] # get mm.until("\n"); # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip mm.tape[mm.cell] = mm.work # put mm.work = '' # clear # comment out this below to remove single line comments # from the output mm.work += "comment*" mm.push(); break #---------------------------------- # parse command words (and abbreviations) # legal characters for keywords (commands) if (not re.match(r"^[abcdefghijklmnopqrstuvwxyzBEKGPRUWS+\-<>0\\^]+$", mm.work)): # error message about a misplaced character mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "!! Misplaced character '" mm.work += mm.tape[mm.cell] # get mm.work += "' in script near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ") \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # my testclass implementation cannot handle complex lists # eg [a-z+-] this is why I have to write out the whole alphabet # while while re.match(r"^[abcdefghijklmnopqrstuvwxyzBEOFKGPRUWS+\-<>0\\^]+$", mm.peep): if mm.eof: break mm.read() #---------------------------------- # KEYWORDS # here we can test for all the keywords (command words) and their # abbreviated one letter versions (eg: clip k, clop K etc). Then # we can print an error message and abort if the word is not a # legal keyword for the parse-edit language # make ll an alias for "lines" and cc an alias for chars if (mm.work == "ll"): mm.work = '' # clear mm.work += "lines" if (mm.work == "cc"): mm.work = '' # clear mm.work += "chars" # one letter command abbreviations if (mm.work == "a"): mm.work = '' # clear mm.work += "add" if (mm.work == "k"): mm.work = '' # clear mm.work += "clip" if (mm.work == "K"): mm.work = '' # clear mm.work += "clop" if (mm.work == "D"): mm.work = '' # clear mm.work += "replace" if (mm.work == "d"): mm.work = '' # clear mm.work += "clear" if (mm.work == "t"): mm.work = '' # clear mm.work += "print" if (mm.work == "p"): mm.work = '' # clear mm.work += "pop" if (mm.work == "P"): mm.work = '' # clear mm.work += "push" if (mm.work == "u"): mm.work = '' # clear mm.work += "unstack" if (mm.work == "U"): mm.work = '' # clear mm.work += "stack" if (mm.work == "G"): mm.work = '' # clear mm.work += "put" if (mm.work == "g"): mm.work = '' # clear mm.work += "get" if (mm.work == "x"): mm.work = '' # clear mm.work += "swap" if (mm.work == ">"): mm.work = '' # clear mm.work += "++" if (mm.work == "<"): mm.work = '' # clear mm.work += "--" if (mm.work == "m"): mm.work = '' # clear mm.work += "mark" if (mm.work == "M"): mm.work = '' # clear mm.work += "go" if (mm.work == "r"): mm.work = '' # clear mm.work += "read" if (mm.work == "R"): mm.work = '' # clear mm.work += "until" if (mm.work == "w"): mm.work = '' # clear mm.work += "while" if (mm.work == "W"): mm.work = '' # clear mm.work += "whilenot" if (mm.work == "n"): mm.work = '' # clear mm.work += "count" if (mm.work == "+"): mm.work = '' # clear mm.work += "a+" if (mm.work == "-"): mm.work = '' # clear mm.work += "a-" if (mm.work == "0"): mm.work = '' # clear mm.work += "zero" if (mm.work == "c"): mm.work = '' # clear mm.work += "chars" if (mm.work == "l"): mm.work = '' # clear mm.work += "lines" if (mm.work == "^"): mm.work = '' # clear mm.work += "escape" if (mm.work == "v"): mm.work = '' # clear mm.work += "unescape" if (mm.work == "z"): mm.work = '' # clear mm.work += "delim" if (mm.work == "S"): mm.work = '' # clear mm.work += "state" if (mm.work == "q"): mm.work = '' # clear mm.work += "quit" if (mm.work == "s"): mm.work = '' # clear mm.work += "write" if (mm.work == "o"): mm.work = '' # clear mm.work += "nop" if (mm.work == "rs"): mm.work = '' # clear mm.work += "restart" if (mm.work == "rp"): mm.work = '' # clear mm.work += "reparse" # some extra syntax for testeof and testtape if (mm.work == "" or mm.work == ""): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "eof*" mm.push(); break if (mm.work == "<==>"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "tapetest*" mm.push(); break if (mm.work == "jump" or mm.work == "jumptrue" or mm.work == "jumpfalse" or mm.work == "testis" or mm.work == "testclass" or mm.work == "testbegins" or mm.work == "testends" or mm.work == "testeof" or mm.work == "testtape"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "The instruction '" mm.work += mm.tape[mm.cell] # get mm.work += "' near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ")\n" mm.work += "can be used in pep assembly code but not scripts. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # show information if these "deprecated" commands are used if (mm.work == "Q" or mm.work == "bail"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "The instruction '" mm.work += mm.tape[mm.cell] # get mm.work += "' near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ")\n" mm.work += "is no longer part of the pep language (july 2020). \n" mm.work += "use 'quit' instead of 'bail', and use 'unstack; print;' \n" mm.work += "instead of 'state'. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "add" or mm.work == "clip" or mm.work == "clop" or mm.work == "replace" or mm.work == "upper" or mm.work == "lower" or mm.work == "cap" or mm.work == "clear" or mm.work == "print" or mm.work == "state" or mm.work == "pop" or mm.work == "push" or mm.work == "unstack" or mm.work == "stack" or mm.work == "put" or mm.work == "get" or mm.work == "swap" or mm.work == "++" or mm.work == "--" or mm.work == "mark" or mm.work == "go" or mm.work == "read" or mm.work == "until" or mm.work == "while" or mm.work == "whilenot" or mm.work == "count" or mm.work == "a+" or mm.work == "a-" or mm.work == "zero" or mm.work == "chars" or mm.work == "lines" or mm.work == "nochars" or mm.work == "nolines" or mm.work == "escape" or mm.work == "unescape" or mm.work == "delim" or mm.work == "quit" or mm.work == "write" or mm.work == "nop" or mm.work == "reparse" or mm.work == "restart"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "word*" mm.push(); break #------------ # the .reparse command and "parse label" is a simple way to # make sure that all shift-reductions occur. It should be used inside # a block test, so as not to create an infinite loop. There is # no "goto" in java so we need to use labelled loops to # implement .reparse/parse> if (mm.work == "parse>"): mm.work = '' # clear mm.work += str(mm.counter) # count if (mm.work != "0"): mm.work = '' # clear mm.work += "script error:\n" mm.work += " extra parse> label at line " mm.work += str(mm.linesRead) # lines mm.work += ".\n" sys.stdout.write(mm.work) # print exit() mm.work = '' # clear mm.work += "# parse> parse label" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "parse>*" mm.push(); # use accumulator to indicate after parse> label mm.counter += 1 # a+ break # -------------------- # implement "begin-blocks", which are only executed # once, at the beginning of the script (similar to awk's BEGIN {} rules) if (mm.work == "begin"): mm.tape[mm.cell] = mm.work # put mm.work += "*" mm.push(); break mm.work += " << unknown command on line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of source file. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # ---------------------------------- # PARSING PHASE: # Below is the parse/compile phase of the script. Here we pop tokens off the # stack and check for sequences of tokens eg "word*semicolon*". If we find a # valid series of tokens, we "shift-reduce" or "resolve" the token series eg # word*semicolon* --> command* # At the same time, we manipulate (transform) the attributes on the tape, as # required. break # parse block while True: #------------------------------------- # 2 tokens #------------------------------------- mm.pop(); mm.pop(); # All of the patterns below are currently errors, but may not # be in the future if we expand the syntax of the parse # language. Also consider: # begintext* endtext* quoteset* notclass*, !* ,* ;* B* E* # It is nice to trap the errors here because we can emit some # (hopefully not very cryptic) error messages with a line number. # Otherwise the script writer has to debug with # pep -a asm.pp -I scriptfile if (mm.work == "word*word*" or mm.work == "word*}*" or mm.work == "word*begintext*" or mm.work == "word*endtext*" or mm.work == "word*!*" or mm.work == "word*,*" or mm.work == "quote*word*" or mm.work == "quote*class*" or mm.work == "quote*state*" or mm.work == "quote*}*" or mm.work == "quote*begintext*" or mm.work == "quote*endtext*" or mm.work == "class*word*" or mm.work == "class*quote*" or mm.work == "class*class*" or mm.work == "class*state*" or mm.work == "class*}*" or mm.work == "class*begintext*" or mm.work == "class*endtext*" or mm.work == "class*!*" or mm.work == "notclass*word*" or mm.work == "notclass*quote*" or mm.work == "notclass*class*" or mm.work == "notclass*state*" or mm.work == "notclass*}*"): mm.work += " (Token stack) \nValue: \n" mm.work += mm.tape[mm.cell] # get mm.work += "\nValue: \n" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.work += "\n" mm.work += "Error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of pep script (missing semicolon?) \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "{*;*" or mm.work == ";*;*" or mm.work == "}*;*"): mm.push(); mm.push(); mm.work += "Error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of pep script: misplaced semi-colon? ; \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == ",*{*"): mm.push(); mm.push(); mm.work += "Error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: extra comma in list? \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "command*;*" or mm.work == "commandset*;*"): mm.push(); mm.push(); mm.work += "Error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: extra semi-colon? \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "!*!*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: \n double negation '!!' is not implemented \n" mm.work += " and probably won't be, because what would be the point? \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "!*{*" or mm.work == "!*;*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: misplaced negation operator (!)? \n" mm.work += " The negation operator precedes tests, for example: \n" mm.work += " !B'abc'{ ... } or !(eof),!'abc'{ ... } \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == ",*command*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: misplaced comma? \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "!*command*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " (at char " mm.work += str(mm.charsRead) # chars mm.work += ") \n" mm.work += " The negation operator (!) cannot precede a command \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == ";*{*" or mm.work == "command*{*" or mm.work == "commandset*{*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: no test for brace block? \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "{*}*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " of script: empty braces {}. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "B*class*" or mm.work == "E*class*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " of script:\n classes ([a-z], [:space:] etc). \n" mm.work += " cannot use the 'begin' or 'end' modifiers (B/E) \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "comment*{*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " of script: comments cannot occur between \n" mm.work += " a test and a brace ({). \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "}*command*"): mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " of script: extra closing brace '}' ?. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() #------------ # The .restart command jumps to the first instruction after the # begin block (if there is a begin block), or the first instruction # of the script. if (mm.work == ".*word*"): mm.work = '' # clear mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if (mm.work == "restart"): mm.work = '' # clear mm.work += str(mm.counter) # count # this is the opposite of .reparse, using run-once loops if (mm.work == "0"): mm.work = '' # clear mm.work += "continue" # before the parse> label if (mm.work == "1"): mm.work = '' # clear mm.work += "break" # after the parse> label mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "reparse"): mm.work = '' # clear mm.work += str(mm.counter) # count # check accumulator to see if we are in the "lex" block # or the "parse" block and adjust the .reparse compilation # accordingly. if (mm.work == "0"): mm.work = '' # clear mm.work += "break" if (mm.work == "1"): mm.work = '' # clear mm.work += "continue" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue mm.push(); mm.push(); mm.work += "error near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script: \n" mm.work += " misplaced dot '.' (use for AND logic or in .reparse/.restart \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() #--------------------------------- # Compiling comments so as to transfer them to the java if (mm.work == "comment*command*" or mm.work == "command*comment*" or mm.work == "commandset*comment*"): 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 += "command*" mm.push(); continue if (mm.work == "comment*comment*"): 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 += "comment*" mm.push(); continue # ----------------------- # negated tokens. # This is a new more elegant way to negate a whole set of # tests (tokens) where the negation logic is stored on the # stack, not in the current tape cell. We just add "not" to # the stack token. # eg: ![:alpha:] ![a-z] ![abcd] !"abc" !B"abc" !E"xyz" # This format is used to indicate a negative test for # a brace block. eg: ![aeiou] { add "< not a vowel"; print; clear; } if (mm.work == "!*quote*" or mm.work == "!*class*" or mm.work == "!*begintext*" or mm.work == "!*endtext*" or mm.work == "!*eof*" or mm.work == "!*tapetest*"): # a simplification: store the token name "quote*/class*/..." # in the tape cell corresponding to the "!*" token. # replace if len(mm.work) != 0: mm.work = mm.work.replace("!*", "not") mm.push(); # this was a bug?? a missing ++; ?? # now get the token-value mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ mm.work = '' # clear continue #----------------------------------------- # format: E"text" or E'text' # This format is used to indicate a "workspace-ends-with" text before # a brace block. if (mm.work == "E*quote*"): mm.work = '' # clear mm.work += "endtext*" mm.push(); mm.work += mm.tape[mm.cell] # get if (mm.work == "\"\""): # empty argument is an error mm.work = '' # clear mm.work += "pep script error near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " empty argument for end-test (E\"\") \n" sys.stdout.write(mm.work) # print exit() if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ mm.work = '' # clear continue #----------------------------------------- # format: B"sometext" or B'sometext' # A 'B' preceding some quoted text is used to indicate a # 'workspace-begins-with' test, before a brace block. if (mm.work == "B*quote*"): mm.work = '' # clear mm.work += "begintext*" mm.push(); mm.work += mm.tape[mm.cell] # get if (mm.work == "\"\""): # empty argument is an error mm.work = '' # clear mm.work += "pep script error near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " empty argument for begin-test (B\"\") \n" sys.stdout.write(mm.work) # print exit() if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ mm.work = '' # clear continue #-------------------------------------------- # ebnf: command := word, ';' ; # formats: "pop; push; clear; print; " etc # all commands need to end with a semi-colon except for # .reparse and .restart if (mm.work == "word*;*"): mm.work = '' # clear # check if command requires parameter mm.work += mm.tape[mm.cell] # get if (mm.work == "add" or mm.work == "until" or mm.work == "while" or mm.work == "whilenot" or mm.work == "mark" or mm.work == "go" or mm.work == "escape" or mm.work == "unescape" or mm.work == "delim" or mm.work == "replace"): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "'" mm.work += mm.tape[mm.cell] # get mm.work += "'" mm.work += " << command needs an argument, on line " mm.work += str(mm.linesRead) # lines mm.work += " of script.\n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "clip"): mm.work = '' # clear # is a work mm.work += "# if len(mm.work) > 0: # clip \n" mm.work += "mm.work = mm.work[:-1] # clip" mm.tape[mm.cell] = mm.work # put if (mm.work == "clop"): mm.work = '' # clear mm.work += "# if len(mm.work) > 0: # clop \n" mm.work += "mm.work = mm.work[1:]; # clop" mm.tape[mm.cell] = mm.work # put if (mm.work == "clear"): mm.work = '' # clear mm.work += "mm.work = '' # clear" mm.tape[mm.cell] = mm.work # put if (mm.work == "upper"): mm.work = '' # clear mm.work += "mm.work = mm.work.upper() # upper" mm.tape[mm.cell] = mm.work # put if (mm.work == "lower"): mm.work = '' # clear mm.work += "mm.work = mm.work.lower() # lower" mm.tape[mm.cell] = mm.work # put # but this does first letter of every word, which is different # to other translation scripts. if (mm.work == "cap"): mm.work = '' # clear mm.work += "mm.work = mm.work.title() # capital" mm.tape[mm.cell] = mm.work # put if (mm.work == "print"): mm.work = '' # clear mm.work += "sys.stdout.write(mm.work) # print" mm.tape[mm.cell] = mm.work # put if (mm.work == "state"): mm.work = '' # clear mm.work += "mm.printState() # state" mm.tape[mm.cell] = mm.work # put if (mm.work == "pop"): mm.work = '' # clear mm.work += "mm.pop();" mm.tape[mm.cell] = mm.work # put if (mm.work == "push"): mm.work = '' # clear mm.work += "mm.push();" mm.tape[mm.cell] = mm.work # put if (mm.work == "unstack"): mm.work = '' # clear mm.work += "while (mm.pop()): continue # unstack " mm.tape[mm.cell] = mm.work # put if (mm.work == "stack"): mm.work = '' # clear mm.work += "while (mm.push()): continue # stack " mm.tape[mm.cell] = mm.work # put if (mm.work == "put"): mm.work = '' # clear mm.work += "mm.tape[mm.cell] = mm.work # put " mm.tape[mm.cell] = mm.work # put if (mm.work == "get"): mm.work = '' # clear mm.work += "mm.work += mm.tape[mm.cell] # get" mm.tape[mm.cell] = mm.work # put if (mm.work == "swap"): mm.work = '' # clear mm.work += "mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work # swap " mm.tape[mm.cell] = mm.work # put if (mm.work == "++"): mm.work = '' # clear mm.work += "mm.increment() # ++ " mm.tape[mm.cell] = mm.work # put if (mm.work == "--"): mm.work = '' # clear mm.work += "if mm.cell > 0: mm.cell -= 1 # --" mm.tape[mm.cell] = mm.work # put if (mm.work == "read"): mm.work = '' # clear mm.work += "mm.read() # read" mm.tape[mm.cell] = mm.work # put if (mm.work == "count"): mm.work = '' # clear mm.work += "mm.work += str(mm.counter) # count " mm.tape[mm.cell] = mm.work # put if (mm.work == "a+"): mm.work = '' # clear mm.work += "mm.counter += 1 # a+ " mm.tape[mm.cell] = mm.work # put if (mm.work == "a-"): mm.work = '' # clear mm.work += "mm.counter -= 1 # a- " mm.tape[mm.cell] = mm.work # put if (mm.work == "zero"): mm.work = '' # clear mm.work += "mm.counter = 0 # zero " mm.tape[mm.cell] = mm.work # put if (mm.work == "chars"): mm.work = '' # clear mm.work += "mm.work += str(mm.charsRead) # chars " mm.tape[mm.cell] = mm.work # put if (mm.work == "lines"): mm.work = '' # clear mm.work += "mm.work += str(mm.linesRead) # lines " mm.tape[mm.cell] = mm.work # put if (mm.work == "nochars"): mm.work = '' # clear mm.work += "mm.charsRead = 0 # nochars " mm.tape[mm.cell] = mm.work # put if (mm.work == "nolines"): mm.work = '' # clear mm.work += "mm.linesRead = 0 # nolines " mm.tape[mm.cell] = mm.work # put # use a labelled loop to quit script. if (mm.work == "quit"): mm.work = '' # clear mm.work += "exit()" mm.tape[mm.cell] = mm.work # put if (mm.work == "write"): mm.work = '' # clear mm.work += "mm.writeToFile()" mm.tape[mm.cell] = mm.work # put # convert to "pass" which does nothing. if (mm.work == "nop"): mm.work = '' # clear mm.work += "pass # nop: no-operation" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue #----------------------------------------- # ebnf: commandset := command , command ; if (mm.work == "command*command*" or mm.work == "commandset*command*"): mm.work = '' # clear mm.work += "commandset*" mm.push(); # format the tape attributes. Add the next command on a newline if mm.cell > 0: mm.cell -= 1 # -- 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.increment() # ++ mm.work = '' # clear continue #------------------- # here we begin to parse "test*" and "ortestset*" and "andtestset*" # #------------------- # eg: B"abc" {} or E"xyz" {} # transform and markup the different test types if (mm.work == "begintext*,*" or mm.work == "endtext*,*" or mm.work == "quote*,*" or mm.work == "class*,*" or mm.work == "eof*,*" or mm.work == "tapetest*,*" or mm.work == "begintext*.*" or mm.work == "endtext*.*" or mm.work == "quote*.*" or mm.work == "class*.*" or mm.work == "eof*.*" or mm.work == "tapetest*.*" or mm.work == "begintext*{*" or mm.work == "endtext*{*" or mm.work == "quote*{*" or mm.work == "class*{*" or mm.work == "eof*{*" or mm.work == "tapetest*{*"): if (mm.work.startswith("begin")): mm.work = '' # clear mm.work += "mm.work.startswith(" if (mm.work.startswith("end")): mm.work = '' # clear mm.work += "mm.work.endswith(" if (mm.work.startswith("quote")): mm.work = '' # clear mm.work += "mm.work == " if (mm.work.startswith("class")): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get # unicode categories are not regexs if (not mm.work.startswith("mm.")): mm.work = '' # clear mm.work += "re.match(r" if (mm.work.startswith("mm.")): mm.work = '' # clear # clear the tapecell for testeof and testtape because # they take no arguments. if (mm.work.startswith("eof")): mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "mm.eof" if (mm.work.startswith("tapetest")): mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "mm.work == mm.tape[mm.cell]" mm.work += mm.tape[mm.cell] # get # a hack if (mm.work.startswith("re.match")): mm.work += ", mm.work" if (not mm.work.startswith("mm.eof") and not mm.work.startswith("mm.work ==") and not mm.work.startswith("mm.work.is") and not mm.work.startswith("mm.is")): mm.work += ")" #!B"mm.eof".!B"mm.work ==" { add ")"; } mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "test*" mm.push(); # the trick below pushes the right token back on the stack. mm.work += mm.tape[mm.cell] # get mm.work += "*" mm.push(); continue #------------------- # negated tests # eg: !B"xyz {} !(eof) {} !(==) {} # !E"xyz" {} # !"abc" {} # ![a-z] {} if (mm.work == "notbegintext*,*" or mm.work == "notendtext*,*" or mm.work == "notquote*,*" or mm.work == "notclass*,*" or mm.work == "noteof*,*" or mm.work == "nottapetest*,*" or mm.work == "notbegintext*.*" or mm.work == "notendtext*.*" or mm.work == "notquote*.*" or mm.work == "notclass*.*" or mm.work == "noteof*.*" or mm.work == "nottapetest*.*" or mm.work == "notbegintext*{*" or mm.work == "notendtext*{*" or mm.work == "notquote*{*" or mm.work == "notclass*{*" or mm.work == "noteof*{*" or mm.work == "nottapetest*{*"): if (mm.work.startswith("notbegin")): mm.work = '' # clear mm.work += "not mm.work.startswith(" if (mm.work.startswith("notend")): mm.work = '' # clear mm.work += "not mm.work.endswith(" if (mm.work.startswith("notquote")): mm.work = '' # clear mm.work += "mm.work != " # re.match(r"hello[0-9]+", 'hello1'): if (mm.work.startswith("notclass")): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get # unicode categories are not regexs if (not mm.work.startswith("mm.")): mm.work = '' # clear mm.work += "not re.match(r" if (mm.work.startswith("mm.")): mm.work = '' # clear mm.work += "not " # clear the tapecell for testeof and testtape because # they take no arguments. if (mm.work.startswith("noteof")): mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "not mm.eof" if (mm.work.startswith("nottapetest")): mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "mm.work != mm.tape[mm.cell]" mm.work += mm.tape[mm.cell] # get # a hack if (mm.work.startswith("not re.match")): mm.work += ", mm.work" if (not mm.work.startswith("not mm.eof") and not mm.work.startswith("mm.work !=") and not mm.work.startswith("not mm.work.is") and not mm.work.startswith("not mm.is")): mm.work += ")" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "test*" mm.push(); # the trick below pushes the right token back on the stack. mm.work += mm.tape[mm.cell] # get mm.work += "*" mm.push(); continue #------------------- # 3 tokens #------------------- mm.pop(); #----------------------------- # some 3 token errors!!! # not a comprehensive list of 3 token errors if (mm.work == "{*quote*;*" or mm.work == "{*begintext*;*" or mm.work == "{*endtext*;*" or mm.work == "{*class*;*" or mm.work == "commandset*quote*;*" or mm.work == "command*quote*;*"): mm.push(); mm.push(); mm.push(); mm.work += "[pep error]\n invalid syntax near line " mm.work += str(mm.linesRead) # lines mm.work += " (char " mm.work += str(mm.charsRead) # chars mm.work += ")" mm.work += " of script (misplaced semicolon?) \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # to simplify subsequent tests, transmogrify a single command # to a commandset (multiple commands). if (mm.work == "{*command*}*"): mm.work = '' # clear mm.work += "{*commandset*}*" mm.push(); mm.push(); mm.push(); continue # errors! mixing AND and OR concatenation if (mm.work == ",*andtestset*{*" or mm.work == ".*ortestset*{*"): # push the tokens back to make debugging easier mm.push(); mm.push(); mm.push(); mm.work += " error: mixing AND (.) and OR (,) concatenation in \n" mm.work += " in pep script near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += ") \n" mm.work += " " mm.work += "\n For example:" mm.work += "\n B\".\".!E\"/\".[abcd./] { print; } # Correct!" mm.work += "\n B\".\".!E\"/\",[abcd./] { print; } # Error! \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() #-------------------------------------------- # ebnf: command := keyword , quoted-text , ";" ; # format: add "text"; if (mm.work == "word*quote*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get if (mm.work == "replace"): # error mm.work += "< command requires 2 parameters, not 1 \n" mm.work += "near line " mm.work += str(mm.linesRead) # lines mm.work += " of script. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # check whether argument is single character, otherwise # throw an error if (mm.work == "escape" or mm.work == "unescape" or mm.work == "while" or mm.work == "whilenot"): # This is trickier than I thought it would be. mm.work = '' # clear mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- # check that arg not empty, (but an empty quote is ok # for the second arg of 'replace' if (mm.work == "\"\""): mm.work = '' # clear mm.work += "[pep error] near line " mm.work += str(mm.linesRead) # lines mm.work += " (or char " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " command '" mm.work += mm.tape[mm.cell] # get mm.work += "\' cannot have an empty argument (\"\") \n" sys.stdout.write(mm.work) # print exit() # quoted text has the quotes still around it. # also handle escape characters like \n \r etc # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop # if len(mm.work) > 0: # clop mm.work = mm.work[1:]; # clop # B "\\" { clip; } # if len(mm.work) > 0: # clip mm.work = mm.work[:-1] # clip if (mm.work != ""): mm.work = '' # clear mm.work += "Pep script error near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " command '" mm.work += mm.tape[mm.cell] # get mm.work += "' takes only a single character argument. \n" sys.stdout.write(mm.work) # print exit() mm.work = '' # clear mm.work += mm.tape[mm.cell] # get if (mm.work == "mark"): mm.work = '' # clear mm.work += "mm.marks[mm.cell] = " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.work += " # mark" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "go"): mm.work = '' # clear # bug! check! mm.work += "mm.goToMark(" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.work += ") # go \n" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "delim"): mm.work = '' # clear # the delimiter should be a single character, no? mm.work += "mm.delimiter = " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.work += " # delim " mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "add"): mm.work = '' # clear mm.work += "mm.work += " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- # handle multiline text # check this! \\n or \n # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\"\nmm.work += \"\\n") mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "while"): mm.work = '' # clear mm.work += "while mm.peep == " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.work += ": # while \n" mm.work += " if mm.eof: break\n mm.read()" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "whilenot"): mm.work = '' # clear mm.work += "while mm.peep != " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- mm.work += ": # whilenot \n" mm.work += " if mm.eof: break\n mm.read()" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "until"): mm.work = '' # clear mm.work += "mm.until(" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- # error until cannot have empty argument if (mm.work == "mm.until(\"\""): mm.work = '' # clear mm.work += "Pep script error near line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " empty argument for 'until' \n" mm.work += " " mm.work += "\n For example:" mm.work += "\n until '.txt'; until \">\"; # correct " mm.work += "\n until ''; until \"\"; # errors! \n" sys.stdout.write(mm.work) # print exit() # handle multiline argument # replace if len(mm.work) != 0: mm.work = mm.work.replace("\n", "\\n") mm.work += ");" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "escape"): mm.work = '' # clear mm.increment() # ++ # argument still has quotes around it # it should be a single character since this has been previously # checked. mm.work += "mm.work = mm.work.replace(" mm.work += mm.tape[mm.cell] # get mm.work += ", mm.escape+" mm.work += mm.tape[mm.cell] # get mm.work += ")" if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue # replace \n with n for example (only 1 character) if (mm.work == "unescape"): mm.work = '' # clear mm.increment() # ++ # use the machine escape char mm.work += "mm.work = mm.work.replace(mm.escape+" mm.work += mm.tape[mm.cell] # get mm.work += ", " mm.work += mm.tape[mm.cell] # get mm.work += ")" if mm.cell > 0: mm.cell -= 1 # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue # error, superfluous argument mm.work += ": command does not take an argument \n" mm.work += "near line " mm.work += str(mm.linesRead) # lines mm.work += " of script. \n" sys.stdout.write(mm.work) # print mm.work = '' # clear #state exit() #---------------------------------- # format: "while [:alpha:] ;" or whilenot [a-z] ; if (mm.work == "word*class*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get if (mm.work == "while"): mm.work = '' # clear mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if (mm.work.startswith("\"^")): mm.work = '' # clear mm.work += "re.match(r" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += ", mm.peep)" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear # category(ch).startswith(cat) mm.work += "# while \n" mm.work += "while " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- # massage code so that the 'peep' is tested, not the # workspace (i.e. mm.isInCategory(mm.peep)) # replace if len(mm.work) != 0: mm.work = mm.work.replace("mm.work", "mm.peep") mm.work += ":\n if mm.eof: break\n mm.read()" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue if (mm.work == "whilenot"): mm.work = '' # clear mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- if (mm.work.startswith("\"^")): mm.work = '' # clear mm.work += "re.match(r" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += ", mm.peep)" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear if mm.cell > 0: mm.cell -= 1 # -- mm.work = '' # clear mm.work += "# whilenot \n" mm.work += "while not " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- # massage code so that the 'peep' is tested, not the # workspace (i.e. mm.isInCategory) # replace if len(mm.work) != 0: mm.work = mm.work.replace("mm.work", "mm.peep") mm.work += ":\n if mm.eof: break\n mm.read()" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "command*" mm.push(); continue # error mm.work += " < command cannot have a class argument \n" mm.work += "line " mm.work += str(mm.linesRead) # lines mm.work += ": error in script \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # arrange the parse> label loops if (mm.eof): if (mm.work == "commandset*parse>*commandset*" or mm.work == "command*parse>*commandset*" or mm.work == "commandset*parse>*command*" or mm.work == "command*parse>*command*"): mm.work = '' # clear # indent both code blocks 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 mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ 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 mm.work = '' # clear if mm.cell > 0: mm.cell -= 1 # -- if mm.cell > 0: mm.cell -= 1 # -- # add a block so that .reparse works before the parse> label. mm.work += "\n# lex block \n" mm.work += "while True: \n" mm.work += mm.tape[mm.cell] # get mm.work += "\n break \n" mm.increment() # ++ mm.increment() # ++ # indent code block # add " "; get; replace "\n" "\n "; put; clear; # python doesnt support labelled loops # add "parse: \n"; mm.work += "\n# parse block \n" mm.work += "while True: \n" mm.work += mm.tape[mm.cell] # get mm.work += "\n break # parse\n" 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 += "commandset*" mm.push(); continue # ------------------------------- # 4 tokens # ------------------------------- mm.pop(); #------------------------------------- # bnf: command := replace , quote , quote , ";" ; # example: replace "and" "AND" ; if (mm.work == "word*quote*quote*;*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get if (mm.work == "replace"): #--------------------------- # a command plus 2 arguments, eg replace "this" "that" mm.work = '' # clear mm.work += "# replace \n" mm.work += "if len(mm.work) != 0: \n" mm.work += " mm.work = mm.work.replace(" mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += ", " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get mm.work += ")\n" 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 += "command*" mm.push(); continue mm.work += "pep script error on line " mm.work += str(mm.linesRead) # lines mm.work += " (character " mm.work += str(mm.charsRead) # chars mm.work += "): \n" mm.work += " command does not take 2 quoted arguments. \n" sys.stdout.write(mm.work) # print exit() #------------------------------------- # format: begin { #* commands *# } # "begin" blocks which are only executed once (they # will are assembled before the "start:" label. They must come before # all other commands. # "begin*{*command*}*", if (mm.work == "begin*{*commandset*}*"): mm.work = '' # clear 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 += "beginblock*" mm.push(); continue # ------------- # parses and compiles concatenated tests # eg: 'a',B'b',E'c',[def],[:space:],[g-k] { ... # these 2 tests should be all that is necessary if (mm.work == "test*,*ortestset*{*" or mm.work == "test*,*test*{*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " or " 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 += "ortestset*{*" mm.push(); mm.push(); continue # dont mix AND and OR concatenations # ------------- # AND logic # parses and compiles concatenated AND tests # eg: 'a',B'b',E'c',[def],[:space:],[g-k] { ... # it is possible to elide this block with the negated block # for compactness but maybe readability is not as good. # negated tests can be chained with non negated tests. # eg: B'http' . !E'.txt' { ... } if (mm.work == "test*.*andtestset*{*" or mm.work == "test*.*test*{*"): mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.work += " and " 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 += "andtestset*{*" mm.push(); mm.push(); continue #------------------------------------- # we should not have to check for the {*command*}* pattern # because that has already been transformed to {*commandset*}* if (mm.work == "test*{*commandset*}*" or mm.work == "andtestset*{*commandset*}*" or mm.work == "ortestset*{*commandset*}*"): mm.work = '' # clear # indent the java code for readability mm.increment() # ++ mm.increment() # ++ 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 # -- mm.work = '' # clear mm.work += "if (" mm.work += mm.tape[mm.cell] # get mm.work += "):\n" mm.increment() # ++ mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # no block end required in python # add "\n}"; 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 += "command*" mm.push(); # always reparse/compile continue # ------------- # multi-token end-of-stream errors # not a comprehensive list of errors... if (mm.eof): if (mm.work.endswith("begintext*") or mm.work.endswith("endtext*") or mm.work.endswith("test*") or mm.work.endswith("ortestset*") or mm.work.endswith("andtestset*")): mm.work += " Error near end of script at line " mm.work += str(mm.linesRead) # lines mm.work += ". Test with no brace block? \n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work.endswith("quote*") or mm.work.endswith("class*") or mm.work.endswith("word*")): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "Error at end of pep script near line " mm.work += str(mm.linesRead) # lines mm.work += ": missing semi-colon? \n" mm.work += "Parse stack: " mm.work += mm.tape[mm.cell] # get mm.work += "\n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work.endswith("{*") or mm.work.endswith("}*") or mm.work.endswith(";*") or mm.work.endswith(",*") or mm.work.endswith(".*") or mm.work.endswith("!*") or mm.work.endswith("B*") or mm.work.endswith("E*")): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "Error: misplaced terminal character at end of script! (line " mm.work += str(mm.linesRead) # lines mm.work += "). \n" mm.work += "Parse stack: " mm.work += mm.tape[mm.cell] # get mm.work += "\n" sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # put the 4 (or less) tokens back on the stack mm.push(); mm.push(); mm.push(); mm.push(); if (mm.eof): sys.stdout.write(mm.work) # print mm.work = '' # clear # create the virtual machine object code and save it # somewhere on the tape. mm.work += "#!/usr/bin/env python3" mm.work += "\n" mm.work += "\n# code generated by \"translate.py.pss\" a pep script" mm.work += "\n# bumble.sf.net/books/pars/" mm.work += "\nimport sys, re # for sys.read(), write() and regex" mm.work += "\nfrom unicodedata import category # for matching classes" mm.work += "\n# may use, which could make the char class code easier" mm.work += "\n# import regex" mm.work += "\n# regex.findall(r\'[[:graph:]]\', \'a \0 \a \b z\') " mm.work += "\n" mm.work += "\nclass Machine: " mm.work += "\n # make a new machine " mm.work += "\n def __init__(self):" mm.work += "\n self.size = 300 # how many elements in stack/tape/marks" mm.work += "\n self.eof = False # end of stream reached?" mm.work += "\n self.charsRead = 0 # how many chars already read" mm.work += "\n self.linesRead = 1 # how many lines already read" mm.work += "\n self.escape = \"\\\\\"" mm.work += "\n self.delimiter = \"*\" # push/pop delimiter (default \"*\")" mm.work += "\n self.counter = 0 # a counter for anything" mm.work += "\n self.work = \"\" # the workspace" mm.work += "\n self.stack = [] # stack for parse tokens " mm.work += "\n self.cell = 0 # current tape cell" mm.work += "\n self.tape = [\"\"]*self.size # a list of attribute for tokens " mm.work += "\n self.marks = [\"\"]*self.size # marked tape cells" mm.work += "\n # or dont initialse peep until \"parse()\" calls \"setInput()\"" mm.work += "\n self.peep = sys.stdin.read(1)" mm.work += "\n" mm.work += "\n def setInput(self, newInput): " mm.work += "\n print(\"to be implemented\")" mm.work += "\n" mm.work += "\n # read one character from the input stream and " mm.work += "\n # update the machine." mm.work += "\n def read(self): " mm.work += "\n if self.eof: System.exit(0)" mm.work += "\n self.charsRead += 1;" mm.work += "\n # increment lines" mm.work += "\n if self.peep == \"\\n\": self.linesRead += 1" mm.work += "\n self.work += self.peep" mm.work += "\n self.peep = sys.stdin.read(1) " mm.work += "\n if not self.peep: self.eof = True" mm.work += "\n" mm.work += "\n # increment the tape pointer (command ++) and increase the " mm.work += "\n # tape and marks array sizes if necessary" mm.work += "\n def increment(self): " mm.work += "\n self.cell += 1" mm.work += "\n if self.cell >= self.size: " mm.work += "\n self.tape.append(\"\")" mm.work += "\n self.marks.append(\"\")" mm.work += "\n self.size += 1" mm.work += "\n" mm.work += "\n # test if all chars in the text are in the unicode category" mm.work += "\n # no! bug! because while checks mm.peep, but class test" mm.work += "\n # checks mm.work. so have to adapt this function for either." mm.work += "\n def isInCategory(self, cat, text): " mm.work += "\n for ch in text:" mm.work += "\n if not category(ch).startswith(cat): return False" mm.work += "\n return True" mm.work += "\n" mm.work += "\n # def " mm.work += "\n # remove escape character: not trivial see perl" mm.work += "\n def unescapeChar(self, c):" mm.work += "\n if len(self.work) > 0:" mm.work += "\n self.work = self.work.replace(\"\\\\\"+c, c)" mm.work += "\n" mm.work += "\n # add escape character : trivial" mm.work += "\n def escapeChar(self, c):" mm.work += "\n if len(self.work) > 0:" mm.work += "\n self.work = self.work.replace(c, \"\\\\\"+c)" mm.work += "\n" mm.work += "\n # a helper function for the multiple escape char bug" mm.work += "\n def countEscaped(self, suffix): " mm.work += "\n count = 0" mm.work += "\n if self.work.endswith(suffix):" mm.work += "\n # removesuffix not available in early python" mm.work += "\n s = self.work.removesuffix(suffix)" mm.work += "\n while s.endswith(self.escape):" mm.work += "\n count += 1" mm.work += "\n s = s.removesuffix(self.escape)" mm.work += "\n return count" mm.work += "\n" mm.work += "\n # reads the input stream until the workspace end with text " mm.work += "\n def until(self, suffix): " mm.work += "\n # read at least one character" mm.work += "\n if self.eof: return" mm.work += "\n self.read()" mm.work += "\n while True: " mm.work += "\n if self.eof: return" mm.work += "\n # no. bug! count the trailing escape chars, odd=continue, even=stop" mm.work += "\n if self.work.endswith(suffix):" mm.work += "\n #and (not self.work.endswith(self.escape + suffix)): " mm.work += "\n if self.countEscaped(suffix) % 2 == 0: return" mm.work += "\n self.read()" mm.work += "\n " mm.work += "\n # pop the first token from the stack into the workspace */" mm.work += "\n def pop(self): " mm.work += "\n if len(self.stack) == 0: return False" mm.work += "\n self.work = mm.stack.pop() + self.work" mm.work += "\n if self.cell > 0: self.cell -= 1" mm.work += "\n return True" mm.work += "\n" mm.work += "\n # push the first token from the workspace to the stack " mm.work += "\n def push(self): " mm.work += "\n # dont increment the tape pointer on an empty push" mm.work += "\n if len(self.work) == 0: return False" mm.work += "\n # need to get this from the delimiter." mm.work += "\n iFirst = self.work.find(self.delimiter);" mm.work += "\n if iFirst == -1:" mm.work += "\n self.stack.append(self.work)" mm.work += "\n self.work = \"\" " mm.work += "\n return True" mm.work += "\n self.stack.append(self.work[0:iFirst+1])" mm.work += "\n self.work = self.work[iFirst+1:]" mm.work += "\n self.increment()" mm.work += "\n return True" mm.work += "\n" mm.work += "\n # this function is not used (the code is \"inlined\") " mm.work += "\n def swap(self): " mm.work += "\n s = self.work" mm.work += "\n self.work = self.tape[self.cell]" mm.work += "\n self.tape[self.cell] = s" mm.work += "\n" mm.work += "\n def goToMark(self, mark):" mm.work += "\n markFound = False " mm.work += "\n length = len(self.marks)" mm.work += "\n for ii in range(length): " mm.work += "\n if (mm.marks[ii] == mark):" mm.work += "\n mm.cell = ii; markFound = True" mm.work += "\n if (markFound == False):" mm.work += "\n print(\"badmark \'\" + mark + \"\'!\") " mm.work += "\n exit()" mm.work += "\n" mm.work += "\n def writeToFile(self): " mm.work += "\n f = open(\"sav.pp\", \"w\")" mm.work += "\n f.write(self.work) " mm.work += "\n f.close() " mm.work += "\n" mm.work += "\n def printState(self): " mm.work += "\n print(\"Stack[\" + \",\".join(self.stack) + " mm.work += "\n \"] Work[\" + self.work + \"] Peep[\" + self.peep + \"]\");" mm.work += "\n print(\"Acc:\" + str(self.counter) + \" Esc:\" + self.escape +" mm.work += "\n \" Delim:\" + self.delimiter + \" Chars:\" + str(self.charsRead) +" mm.work += "\n \" Lines:\" + str(self.linesRead) + \" Cell:\" + str(self.cell));" mm.work += "\n" mm.work += "\n # this is where the actual parsing/compiling code should go" mm.work += "\n # so that it can be used by other python classes/objects. Also" mm.work += "\n # should have a stream argument." mm.work += "\n def parse(self, s): " mm.work += "\n # a reset or \"setinput()\" method would be useful to parse a " mm.work += "\n # different string/file/stream, without creating a new" mm.work += "\n # machine object." mm.work += "\n # could use code like this to check if input is string or file" mm.work += "\n if isinstance(s, file):" mm.work += "\n print(\"\")" mm.work += "\n # self.reset(s)" mm.work += "\n # self.reader = s" mm.work += "\n elif isinstance(s, string):" mm.work += "\n f = StringIO.StringIO(\"test\")" mm.work += "\n for line in f: print(line)" mm.work += "\n else:" mm.work += "\n f = sys.stdin" mm.work += "\n sys.stdout.write(\"not implemented\")" mm.work += "\n" mm.work += "\n" mm.work += "\n# end of Machine class definition" mm.work += "\n" mm.work += "\n# will become:" mm.work += "\n# mm.parse(sys.stdin) or " mm.work += "\n# mm.parse(\"abcdef\") or" mm.work += "\n# open f; mm.parse(f)" mm.work += "\n" mm.work += "\ntemp = \"\" " mm.work += "\nmm = Machine() \n" # save the code in the current tape cell mm.tape[mm.cell] = mm.work # put mm.work = '' # clear #--------------------- # check if the script correctly parsed (there should only # be one token on the stack, namely "commandset*" or "command*"). mm.pop(); mm.pop(); if (mm.work == "commandset*" or mm.work == "command*"): mm.work = '' # clear # indent generated code (6 spaces) for readability. 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 mm.work = '' # clear # restore the java preamble from the tape mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0: mm.cell -= 1 # -- #add 'script: \n'; mm.work += "while (not mm.eof): \n" mm.work += mm.tape[mm.cell] # get # not end block marker required in python #add "\n}\n"; mm.work += "\n\n# end of code generated by tr/translate.py.pss \n" # put a copy of the final compilation into the tapecell # so it can be inspected interactively. mm.tape[mm.cell] = mm.work # put sys.stdout.write(mm.work) # print mm.work = '' # clear exit() if (mm.work == "beginblock*commandset*" or mm.work == "beginblock*command*"): mm.work = '' # clear # indentation not needed here #add ""; get; #replace "\n" "\n"; put; clear; # indent main code for readability. mm.increment() # ++ 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 mm.work = '' # clear if mm.cell > 0: mm.cell -= 1 # -- # get java preamble from tape 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.work += mm.tape[mm.cell] # get mm.work += "\n" mm.increment() # ++ # a labelled loop for "quit" (but quit can just exit?) #add "script: \n"; mm.work += "while (not mm.eof): \n" mm.work += mm.tape[mm.cell] # get # not end block marker required in python #add "\n}\n"; mm.work += "\n\n# end of generated code\n" # put a copy of the final compilation into the tapecell # for interactive debugging. mm.tape[mm.cell] = mm.work # put sys.stdout.write(mm.work) # print mm.work = '' # clear exit() mm.push(); mm.push(); # try to explain some more errors while (mm.pop()): continue # unstack if (mm.work.startswith("parse>")): mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "[error] pep syntax error:\n" mm.work += " The parse> label cannot be the 1st item \n" mm.work += " of a script \n" sys.stdout.write(mm.work) # print exit() mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work = '' # clear mm.work += "After compiling with 'translate.python.pss' (at EOF): \n " mm.work += " parse error in input script. \n " sys.stdout.write(mm.work) # print mm.work = '' # clear while (mm.pop()): continue # unstack mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "Parse stack: " mm.work += mm.tape[mm.cell] # get mm.work += "\n" mm.work += " * debug script " mm.work += " >> pep -If script -i 'some input' \n " mm.work += " * debug compilation. \n " mm.work += " >> pep -Ia asm.pp script' \n " sys.stdout.write(mm.work) # print mm.work = '' # clear exit() # not eof # there is an implicit .restart command here (jump start) break # parse # end of code generated by tr/translate.py.pss