#!/usr/bin/ruby # code generated by "translate.ruby.pss" a pep script # http://bumble.sf.net/books/pars/tr/ # require 'something' class Machine # make a new machine attr_accessor :work, :charsRead, :linesRead, :escape, :delimiter, :counter, :stack, :tape, :cell, :marks, :eof, :peep def initialize() @size = 300 # how many elements in stack/tape/marks @eof = false # end of stream reached? @charsRead = 0 # how many chars already read @linesRead = 1 # how many lines already read @escape = "\\" @delimiter = "*" # push/pop delimiter (default "*") @counter = 0 # a counter for anything @work = "" # the workspace @stack = [] # stack for parse tokens @cell = 0 # current tape cell @tape = Array.new(@size) {String.new} # a list of attribute for tokens @marks = Array.new(@size) {String.new} # marked tape cells # or dont initialse peep until "parse()" calls "setInput()" @peep = ARGF.readchar end def setInput(newInput) puts "to be implemented" end # read one character from the input stream and # update the machine. def read if @eof then exit end @charsRead += 1; # increment lines if @peep == "\n" then @linesRead += 1 end @work += @peep @peep = ARGF.readchar if @peep.nil? then @eof = true; end end # test if all chars in workspace are in unicode category def isInCategory(cat) #for ch in @work # if not category(ch).start_with?(cat) then return false end #return True end # this needs to actually walk the string # eg "abcab\cabc" # not trivial def unescapeChar(c) @work.gsub!("#{@escape}#{c}", c) end # add escape character : trivial? def escapeChar(c) @work.gsub!(c, @escape+c) end # a helper for the multiescape until bug def countEscaped(suffix) count = 0 #s = @work.sub(/#{suffix}$/, "") s = @work.delete_suffix(suffix) while s.end_with?(@escape) count += 1 s.delete_suffix!(@escape) end # puts "count=#{count}" return count end # reads the input stream until the workspace end with text def until(suffix) # read at least one character if @eof then return end self.read() while true do if @eof then return end # need to count the @escape chars preceding suffix # if odd, keep reading, if even, stop if @work.end_with?(suffix) then if (self.countEscaped(suffix).even?) then return end end self.read() end end # this implements the ++ command incrementing the tape pointer # and growing the tape and marks arrays if required def increment() @cell += 1 if @cell >= @size then @tape.append("") @marks.append("") @size += 1 end end # pop the first token from the stack into the workspace */ def pop() if @stack.length == 0 then return false end @work = @stack.pop() + @work if @cell > 0 then @cell -= 1 end return true end # push the first token from the workspace to the stack def push() # dont increment the tape pointer on an empty push if @work == "" then return false end # need to get this from the delimiter. iFirst = @work.index(@delimiter) if iFirst.nil? @stack.push(@work); @work = ""; return true # also @stack << @work end # s[i..j] means all chars from i to j # s[i,n] means n chars from i @stack.push(@work[0..iFirst]) @work = @work[iFirst+1..-1] self.increment() return true end def printState() puts "Stack[#{@stack.join(', ')}] Work[#{@work}] Peep[#{@peep}]" puts "Acc:#{@counter} Esc:#{@escape} Delim:#{@delimiter} Chars:#{@charsRead}" + " Lines:#{@linesRead} Cell:#{@cell}" end def goToMark(mark) ii = @marks.find_index(mark) if !ii.nil? then @cell = ii else print("bad mark '" + mark + "'!") exit end end # this is where the actual parsing/compiling code should go # so that it can be used by other ruby classes/objects. Also # should have a stream argument. def parse(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("") # @reset(s) # @reader = s #elseif isinstance(s, string) #f = StringIO.StringIO("test") #for line in f print(line) #else # f = STDIN #end #puts "not implemented" end end # end of Machine class definition # will become: # mm.parse(sys.stdin) or # mm.parse("abcdef") or # open f; mm.parse(f) # the restart flag, which allows .restart to work before the # parse label, in languages (like ruby) that dont have # labelled loops restart = false mm = Machine.new while !mm.eof do # lex block while true mm.read() # read # make character numbers (for error messages) relative # to line numbers if (mm.work == "\n") then mm.work = '' # clear mm.charsRead = 0 # nochars break end if (mm.work.match?(/^[[:space:]]+$/)) then mm.work = '' # clear break end if (mm.work == "+" || mm.work == "-") then mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "opadd*" mm.push(); break end if (mm.work == "*" || mm.work == "/") then mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "opmul*" mm.push(); break end # modern pascal style comments, but not (* ... *) because # they are tricky to parse. if (mm.work == "{") then # save the line number for possible error message later mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "{" mm.until("}"); if (mm.work.end_with?("}")) then # 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 end # 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" print mm.work # print mm.work = '' # clear exit end if (mm.work == "*" || mm.work == "/") then mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "opmul*" mm.push(); break end # 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 == "." || mm.work == "," || mm.work == "=" || mm.work == ";" || mm.work == "(" || mm.work == ")") then mm.tape[mm.cell] = mm.work # put mm.work += "*" mm.push(); break end if (mm.work == "!") then mm.work = '' # clear mm.work += "write" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "!*" mm.push(); break end if (mm.work == "?") then mm.work = '' # clear mm.work += "read" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "?*" mm.push(); break end # also need to parse <= >= comparison operators # '=' is comparison and also constant assignment. if (mm.work == "<" || mm.work == ">" || mm.work == "#") then # while while /^[=]+$/.match?(mm.peep) if mm.eof then break end mm.read() end if (mm.work != "<" && mm.work != ">" && mm.work != ">=" && mm.work != "<=" && mm.work != "#") then # 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 += mm.linesRead.to_s # lines mm.work += "/" mm.work += mm.charsRead.to_s # chars mm.work += "\n" print mm.work # print exit end if (mm.work == "#") then mm.work = '' # clear mm.work += "!=" end mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "compare*" mm.push(); end if (mm.work == ":") then if (mm.eof) then mm.work = '' # clear mm.work += "trailing : at end of file!\n" print mm.work # print exit end mm.read() # read if (mm.work == ":=") then mm.tape[mm.cell] = mm.work # put mm.work += "*" mm.push(); break end 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 += mm.linesRead.to_s # lines mm.work += "/" mm.work += mm.charsRead.to_s # chars mm.work += "\n" print mm.work # print exit end if (mm.work.match?(/^[0-9]+$/)) then # while while /^[0-9]+$/.match?(mm.peep) if mm.eof then break end mm.read() end mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "number*" mm.push(); break end if (mm.work.match?(/^[[:alpha:]]+$/)) then # while while /^[[:alpha:]]+$/.match?(mm.peep) if mm.eof then break end mm.read() end # make keywords case insensitive mm.tape[mm.cell] = mm.work # put mm.work.downcase! # lower # synonym with ! if (mm.work == "write" || mm.work == "writeln") then mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "!*" mm.push(); break end # keywords in pl/0 if (mm.work == "const" || mm.work == "var" || mm.work == "if" || mm.work == "then" || mm.work == "while" || mm.work == "do" || mm.work == "begin" || mm.work == "end" || mm.work == "proc" || mm.work == "procedure" || mm.work == "call" || mm.work == "odd") then # 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") then mm.work = '' # clear mm.work += "proc" end mm.work += "*" mm.push(); break end # 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 end if (mm.work != "") then # error unrecognised character mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] incorrect character '" mm.work += mm.tape[mm.cell] # get mm.work += "'\n" print mm.work # print exit end break end if restart then restart = false; next; end # parse block while true # To visualise token reduction uncomment this below: mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " " print mm.work # print mm.work = '' # clear mm.work += "\n" while mm.pop() do next end # unstack print mm.work # print if !mm.work.empty? then # clip mm.work = mm.work[0..-2] # clip end while mm.push() do next end # 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.start_with?("if*condition*then*statement*") && mm.work != "if*condition*then*statement*") then # replace if mm.work.length > 0 then mm.work.gsub!("if*condition*then*statement*", "statement*") end mm.push(); mm.push(); if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put if mm.cell > 0 then mm.cell -= 1; end # -- mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ next end if (mm.work.start_with?("while*condition*do*statement*") && mm.work != "while*condition*do*statement*") then # replace if mm.work.length > 0 then mm.work.gsub!("while*condition*do*statement*", "statement*") end mm.push(); mm.push(); if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put if mm.cell > 0 then mm.cell -= 1; end # -- mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ next end mm.push(); mm.push(); mm.push(); mm.push(); mm.push(); #----------------- # 1 token mm.pop(); # errors if (mm.eof && mm.work != ".*") then mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] Missing '.' at end of program ? \n" mm.work += " \n" print mm.work # print exit end #----------------- # 2 tokens mm.pop(); # Some errors if (mm.work == "ident*ident*") then mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] 2 variable names in a row (is there a \n" mm.work += " missing operator?) \n" print mm.work # print exit end if (mm.work == "vardec*const*") then mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] Constant declarations must precede variable \n" mm.work += " declarations in pl/0 \n" print mm.work # print exit end if (mm.work == "condec*const*") then mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] only 1 constant declaration block is allowed \n" mm.work += " in each scope \n" print mm.work # print exit end if (mm.work == "vardec*var*") then mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] only 1 variable declaration block is allowed \n" mm.work += " in each scope \n" print mm.work # print exit end if (mm.work == ";*end*") then mm.work = '' # clear mm.work += mm.linesRead.to_s # lines mm.work += ":" mm.work += mm.charsRead.to_s # chars mm.work += " [pl/0 error] Last statement in block does not require \n" mm.work += " a semi-colon ';' \n" print mm.work # print exit end # 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.end_with?("proc*") && !mm.work.start_with?("procset*")) then if (mm.work != "proc*") then # 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 then mm.cell -= 1; end # -- mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "procset*proc*" mm.push(); mm.push(); next end # 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 then mm.cell -= 1; end # -- mm.work = '' # clear mm.tape[mm.cell] = mm.work # put mm.work += "procset*proc*" mm.push(); mm.push(); next end # procedure headers (name etc) if (mm.work == "procset*proceed*") then 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 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "procset*" mm.push(); next end # "=" can be used for constant assignment but also as # a comparison operator if (mm.work == "=*ident*" || mm.work == "=*exp*") then # replace if mm.work.length > 0 then mm.work.gsub!("=*", "compare*") end mm.push(); mm.push(); next end if (mm.work == "exp*=*") then # replace if mm.work.length > 0 then mm.work.gsub!("=*", "compare*") end mm.push(); mm.push(); next end # expression transmog if (mm.work == "opmul*ident*" || mm.work == "opadd*ident*" || mm.work == "opmul*number*" || mm.work == "opadd*number*" || mm.work == "compare*ident*" || mm.work == "compare*number*" || mm.work == ":=*ident*" || mm.work == ":=*number*" || mm.work == "if*ident*" || mm.work == "if*number*" || mm.work == "while*ident*" || mm.work == "while*number*" || mm.work == "(*ident*" || mm.work == "(*number*" || mm.work == "!*ident*" || mm.work == "!*number*") then mm.push(); mm.work = '' # clear mm.work += "exp*" mm.push(); next end # expression transmutation if (mm.work == "ident*opmul*" || mm.work == "ident*opadd*" || mm.work == "number*opmul*" || mm.work == "number*opadd*" || mm.work == "ident*compare*" || mm.work == "number*compare*") then # replace if mm.work.length > 0 then mm.work.gsub!("ident*", "exp*") end # replace if mm.work.length > 0 then mm.work.gsub!("number*", "exp*") end mm.push(); mm.push(); next end if (mm.work == "const*conlist*") then 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 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "condec*" mm.push(); next end # non-tail reduction for variables if (mm.work == "var*ident*") then 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 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "varlist*" mm.push(); next end # variable decs if (mm.work == "varlist*;*") then mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "vardec*" mm.push(); next end if (mm.work == "block*.*") then mm.work = '' # clear mm.work += "program*" mm.push(); next end if (mm.work == "call*ident*") then 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 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); next end if (mm.work == "?*ident*") then mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); next end # a multi statement block, between begin/end if (mm.work == "begin*statementset*") then # 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 then mm.cell -= 1; end # -- # replace if mm.work.length > 0 then mm.work.gsub!("\n", "\n ") end mm.work += "\nend" mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); next end # tail reduction for statementsets if (mm.work == "statement*end*") then mm.work = '' # clear #get; ++; get; --; put; clear; mm.work += "statementset*" mm.push(); next end #----------------- # 3 tokens mm.pop(); # ! expression must be parsed while looked at the # trailing token, like all expression parsing if (mm.work.start_with?("!*exp*") && mm.work != "!*exp*" && !mm.work.end_with?("opmul*") && !mm.work.end_with?("opadd*")) then # need to conserve the "invisible" last token # replace if mm.work.length > 0 then mm.work.gsub!("!*exp*", "statement*") end mm.push(); mm.push(); # also transfer attributes if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.work += mm.tape[mm.cell] # get mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ next end # procedure headers (name etc) if (mm.work == "proc*ident*;*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "prochead*" mm.push(); next end # procedure headers (name etc) if (mm.work == "prochead*statement*;*") then # indent the statement if it is not a begin/end construct mm.work = '' # clear mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if (!mm.work.start_with?("begin")) then mm.work = '' # clear mm.work += " " mm.work += mm.tape[mm.cell] # get # replace if mm.work.length > 0 then mm.work.gsub!("\n", "\n ") end mm.tape[mm.cell] = mm.work # put end if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "proceed*" mm.push(); next end # expressions, this could be the trickiest aspect of # the grammar. transmog ident/number to exp if (mm.work == "exp*opmul*exp*" || mm.work == "exp*opadd*exp*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "exp*" mm.push(); next end if (mm.work == "(*exp*)*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "exp*" mm.push(); next end # 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*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statementset*" mm.push(); next end # variable decs if (mm.work == "varlist*,*ident*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "varlist*" mm.push(); next end #----------------- # 4 tokens mm.pop(); # procedure headers (name etc). Need to indent the variable decs etc if (mm.work == "prochead*vardec*statement*;*" || mm.work == "prochead*condec*statement*;*") then # indent the variable/constant declaration mm.work = '' # clear mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # replace if mm.work.length > 0 then mm.work.gsub!("\n", "\n ") end mm.tape[mm.cell] = mm.work # put if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "proceed*" mm.push(); next end # ident and number have already been transmog'ed into exp* # and =* into compare* if (mm.work.start_with?("exp*compare*exp*") && mm.work != "exp*compare*exp*" && !mm.work.end_with?("opmul*") && !mm.work.end_with?("opadd*")) then # need to conserve the "invisible" last token # replace if mm.work.length > 0 then mm.work.gsub!("exp*compare*exp*", "condition*") end mm.push(); mm.push(); if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.increment() # ++ mm.work = '' # clear next end # also see the 5 token reduction, because of the trailing token # required by exp* if (mm.work == "if*condition*then*statement*" || mm.work == "while*condition*do*statement*") then # 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 (!mm.work.start_with?("begin")) then mm.work = '' # clear mm.work += " " mm.work += mm.tape[mm.cell] # get # replace if mm.work.length > 0 then mm.work.gsub!("\n", "\n ") end mm.tape[mm.cell] = mm.work # put end if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "statement*" mm.push(); next end # 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.start_with?("ident*:=*exp*") && mm.work != "ident*:=*exp*" && !mm.work.end_with?("opmul*") && !mm.work.end_with?("opadd*")) then # need to conserve the "invisible" last token # replace if mm.work.length > 0 then mm.work.gsub!("ident*:=*exp*", "statement*") end mm.push(); mm.push(); if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.increment() # ++ mm.increment() # ++ next end # tail reduction for constant decs if (mm.work == "ident*=*number*;*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "conlist*" mm.push(); next end # if (mm.work == "ident*;*") then mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "varlist*" mm.push(); next end #----------------- # 5 tokens mm.pop(); # procedure headers (name etc), need to indent condec vardec if (mm.work == "prochead*condec*vardec*statement*;*") then # indent the variable and constant declarations mm.work = '' # clear mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # replace if mm.work.length > 0 then mm.work.gsub!("\n", "\n ") end mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += " " mm.increment() # ++ mm.work += mm.tape[mm.cell] # get # replace if mm.work.length > 0 then mm.work.gsub!("\n", "\n ") end mm.tape[mm.cell] = mm.work # put if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "proceed*" mm.push(); next end # constant declarations, tail reduction, but tail redux not # necessary if (mm.work == "ident*=*number*,*conlist*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "conlist*" mm.push(); next end # program reduction if (mm.eof) then if (mm.work == "statement*.*") then mm.work = '' # clear mm.work += mm.tape[mm.cell] # get mm.increment() # ++ mm.work += mm.tape[mm.cell] # get if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" end if (mm.work == "vardec*statement*.*" || mm.work == "condec*statement*.*" || mm.work == "procset*statement*.*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" end if (mm.work == "condec*vardec*statement*.*" || mm.work == "vardec*procset*statement*.*" || mm.work == "condec*procset*statement*.*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" end if (mm.work == "condec*vardec*procset*statement*.*") then 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 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- if mm.cell > 0 then mm.cell -= 1; end # -- mm.tape[mm.cell] = mm.work # put mm.work = '' # clear mm.work += "program*" end end if (mm.eof) then while mm.pop() do next end # unstack if (mm.work == "program*") then 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" print mm.work # print exit end 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" print mm.work # print exit end mm.push(); mm.push(); mm.push(); mm.push(); mm.push(); break end # parse end # end of generated code