Created
July 18, 2010 07:06
-
-
Save ChadyG/480195 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Parser specification for TigerBehavior | |
# | |
class TigerBehavior | |
token ON SELF MY FOR GO TO THEN THE LEAVE COME BACK FROM WAKE UP SLEEP AM PM AT IS NOW LOW HIGH NORMAL | |
HALF AN HOUR | |
ABOUT AROUND | |
JUST OVER UNDER NO THAN LONGER SHORTER DO NOT | |
JAN FEB MAR APR MAY JUNE JULY AUG SEPT OCT NOV DEC | |
MINUTES HOURS SECONDS | |
WORD NUMBER TWODIGIT FOURDIGIT COLON COMMA PULSE RESTLESSNESS BALANCE IN BY BEFORE AFTER EARLIER LATER | |
rule | |
script: day_List | |
{ | |
p = Tree.new(:SCRIPT) | |
p.child = val[0] | |
p.lineno = val[0].lineno | |
result = p | |
return result | |
} | |
day_List: day day_List | |
{ | |
p = Tree.new(:DAYS) | |
p.child = val[0] | |
p.next = val[2] | |
p.lineno = val[0][1][1] | |
return p | |
} | |
| # empty | |
{ | |
return nil | |
} | |
day: ON date action_List | |
{ | |
p = Tree.new(:DAY) | |
p.child = val[0] | |
p.lineno = val[0][1][1] | |
return p | |
} | |
action_List: action action_List | |
{ | |
p = Tree.new(:ACTIONS) | |
p.child = val[0] | |
p.next = val[2] | |
p.lineno = val[0].lineno | |
return p | |
} | |
| # empty | |
{ | |
return nil | |
} | |
## | |
# Begin Actions | |
## | |
action: wakeAction | |
| sleepAction | |
| leaveAction | |
| returnAction | |
| moveAction | |
| alterAction | |
| removeAction | |
| paramMod | |
wakeAction: SELF WAKE time THEN | |
{ | |
p = Tree.new(:WAKEACTION) | |
p.time['mod'] = val[2].to_s | |
p.time['time'] = val[3].to_s | |
p.lineno = val[0][1][1] | |
return p | |
} | |
sleepAction: SELF SLEEP | |
{ | |
p = Tree.new(:SLEEPACTION) | |
p.lineno = val[0][1][1] | |
return p | |
} | |
leaveAction: SELF LEAVE leavePreposition | |
{ | |
p = Tree.new(:LEAVEACTION) | |
p.actionName = val[2] | |
p.lineno = val[0][1][1] | |
return p | |
} | |
returnAction: SELF returnt returnPreposition time | |
{ | |
p = Tree.new(:RETURNACTION) | |
p.actionName = val[2] | |
p.time['mod'] = val[3].to_s | |
p.time['time'] = val[4].to_s | |
p.lineno = val[0][1][1] | |
return p | |
} | |
moveAction: SELF goTo article location movePreposition time THEN | |
{ | |
p = Tree.new(:MOVEACTION) | |
p.actionName = val[4] | |
p.location = val[3] | |
p.time['mod'] = val[5].to_s | |
p.time['time'] = val[6].to_s | |
p.lineno = val[0][1][1] | |
return p | |
} | |
alterAction: SELF actionName alterPreposition | |
{ | |
p = Tree.new(:ALTERACTION) | |
p.actionName = val[1] | |
p.time = val[2] | |
p.lineno = val[0][1][1] | |
return p | |
} | |
orderAction: SELF NOW goTo article word_list orderChange word_list | |
{ | |
p = Tree.new(:ORDERACTION) | |
p.actionName = val[3] | |
p.location = val[4] | |
p.time['mod'] = val[5].to_s | |
p.time['time'] = val[6].to_s | |
p.lineno = val[0][1][1] | |
return p | |
} | |
removeAction: SELF stop actionName | |
{ | |
p = Tree.new(:REMOVEACTION) | |
p.actionName = val[2] | |
p.lineno = val[0][1][1] | |
return p | |
} | |
# Prepositions | |
leavePreposition: FOR word_list | |
{ | |
return val[1] | |
} | |
| # empty | |
{ | |
return "" | |
} | |
returnPreposition: FROM word_list | |
{ | |
return val[1] | |
} | |
| # empty | |
{ | |
return "" | |
} | |
movePreposition: TO actionName | |
{ | |
return val[1] | |
} | |
| # empty | |
{ | |
return "" | |
} | |
alterPreposition: time timePost | |
{ | |
p = Tree.new(:ALTERTIME) | |
p.time['mod'] = val[1] | |
p.time['time'] = val[0] | |
p.lineno = val[0][1] | |
return p | |
} | |
| IN article location | |
{ | |
p = Tree.new(:ALTERLOCATION) | |
p.location = val[2] | |
p.lineno = val[0][1] | |
return p | |
} | |
actionName: verb | |
{ | |
return val[0] | |
} | |
| word_list | |
{ | |
return val[0] | |
} | |
paramMod: MY param isNow value | |
{ | |
p = Tree.new(:PARAMMOD) | |
p.pmod[0] = val[1] | |
p.pmod[2] = val[3] | |
p.lineno = val[0][1] | |
return p | |
} | |
orderChange: BEFORE | |
{ | |
return :before | |
} | |
| AFTER | |
{ | |
return :after | |
} | |
## | |
# End Actions | |
# Begin Time Stuff | |
## | |
timePre: ABOUT | |
{ | |
return val[0][0] | |
} | |
| AROUND | |
{ | |
return val[0][0] | |
} | |
| justOver | |
{ | |
return val[0] | |
} | |
| justUnder | |
{ | |
return val[0] | |
} | |
| lessEq | |
{ | |
return val[0] | |
} | |
| greatEq | |
{ | |
return val[0] | |
} | |
timePost: EARLIER | |
{ | |
return val[0][0] | |
} | |
| LATER | |
{ | |
return val[0][0] | |
} | |
meridian: AM | |
{ | |
return 'AM' | |
} | |
| PM | |
{ | |
return 'PM' | |
} | |
timeUnit: MINUTES | |
{ | |
return 'm' | |
} | |
| HOURS | |
{ | |
return 'h' | |
} | |
| SECONDS | |
{ | |
return 's' | |
} | |
| halfHour | |
{ | |
return val[0] | |
} | |
month: JAN | |
{ | |
return val[0][0] | |
} | |
| FEB | |
{ | |
return val[0][0] | |
} | |
| MAR | |
{ | |
return val[0][0] | |
} | |
| APR | |
{ | |
return val[0][0] | |
} | |
| MAY | |
{ | |
return val[0][0] | |
} | |
| JUNE | |
{ | |
return val[0][0] | |
} | |
| JULY | |
{ | |
return val[0][0] | |
} | |
| AUG | |
{ | |
return val[0][0] | |
} | |
| SEPT | |
{ | |
return val[0][0] | |
} | |
| NOV | |
{ | |
return val[0][0] | |
} | |
| DEC | |
{ | |
return val[0][0] | |
} | |
time: timePoint | |
{ | |
return val[0] | |
} | |
| timePre duration | |
{ | |
t = parseTime(val[1]) | |
seconds = timeToSeconds(t) | |
case val[0] | |
when :ABOUT | |
low = {}.merge(t) | |
high = {}.merge(t) | |
low['seconds'] = [0, low['seconds']-5].min | |
low['minutes'] = [0, low['minutes']-5].min | |
low['hours'] = [0, low['hours']-5].min | |
high['seconds'] = high['seconds']+5 unless high['seconds'].zero? | |
high['minutes'] = high['minutes']+5 unless high['minutes'].zero? | |
high['hours'] = high['hours']+5 unless high['hours'].zero? | |
low = timeToSeconds(low) | |
high = timeToSeconds(high) | |
return [secondsToString(low), secondsToString(high)] | |
when :AROUND | |
onethird = s/3 | |
return [secondsToString(s - onethird), secondsToString(s + onethird)] | |
when :OVER | |
high = {}.merge(t) | |
high['seconds'] = high['seconds']+5 unless high['seconds'].zero? | |
high['minutes'] = high['minutes']+5 unless high['minutes'].zero? | |
high['hours'] = high['hours']+5 unless high['hours'].zero? | |
high = timeToSeconds(high) | |
return [val[1], secondsToString(high)] | |
when :UNDER | |
low = {}.merge(t) | |
low['seconds'] = [0, low['seconds']-5].min | |
low['minutes'] = [0, low['minutes']-5].min | |
low['hours'] = [0, low['hours']-5].min | |
low = timeToSeconds(low) | |
return [secondsToString(low), val[1]] | |
else | |
return [val[1],val[1]] | |
end | |
} | |
| duration | |
{ | |
t = parseTime(val[0]) | |
seconds = timeToSeconds(t) | |
return [val[0],val[0]] | |
} | |
timePoint: hourDigits minuteTime meridian | |
{ | |
return val[0].to_s + ':' + val[1].to_s + ' ' + val[2].to_s | |
} | |
duration: NUMBER timeUnit | |
{ | |
return val[0][0].to_s + val[1].to_s | |
} | |
date: month NUMBER COMMA year | |
{ | |
return val[0].to_s + ' ' + val[1][1][0].to_s + ', ' + val[3].to_s | |
} | |
year: FOURDIGIT | |
{ | |
return val[1][1][0].to_s | |
} | |
minuteTime: COLON TWODIGIT | |
{ | |
return val[1][1][0].to_s + 'm' | |
} | |
| # empty | |
{ | |
return '' | |
} | |
hourDigits: NUMBER | |
{ | |
return val[0][1][0].to_s + 'h' | |
} | |
| TWODIGIT | |
{ | |
return val[0][1][0].to_s + 'h' | |
} | |
halfHour: HALF AN HOUR | |
{ | |
return "30m" | |
} | |
# End Time Stuff | |
# Begin Extra | |
## | |
returnt: COME BACK FROM | |
goTo: GO TO | |
wakeUp: WAKE UP | |
isNow: IS NOW | |
justOver: JUST OVER | |
{ | |
return val[1][1] | |
} | |
justUnder: JUST UNDER | |
{ | |
return val[1][1] | |
} | |
lessEq: NO LONGER THAN | |
greatEq: NO SHORTER THAN | |
stop: DO NOT #NO LONGER | |
location: word_list | |
{ | |
return val[0] | |
} | |
param: PULSE | |
{ | |
return :pulse | |
} | |
| RESTLESSNESS | |
{ | |
return :restlessness | |
} | |
| BALANCE | |
{ | |
return :balance | |
} | |
value: NUMBER | |
{ | |
return val[0][0] | |
} | |
| LOW | |
{ | |
return :low | |
} | |
| NORMAL | |
{ | |
return :normal | |
} | |
| HIGH | |
{ | |
return :high | |
} | |
word_list: WORD word_list | |
{ | |
return val[0][0].to_s + val[1].to_s | |
} | |
| # empty | |
{ | |
return "" | |
} | |
verb: WAKE | |
{ | |
return :wake | |
} | |
| SLEEP | |
{ | |
return :sleep | |
} | |
| LEAVE | |
{ | |
return :leave | |
} | |
article: THE | |
| # emtpy | |
## | |
# End Extra | |
## | |
end | |
---- header | |
class Tree | |
attr_accessor :nodeTag, :nodeName, :child, :next, :actionName, :location, :time, :pmod, :lineno | |
def initialize(production) | |
@nodeTag = production | |
@child = nil | |
@next = nil | |
@nodeName = nil | |
@actionName = nil | |
@location = nil | |
@pmod = [] #param mod [strname, value] | |
@time = {} #time hash 'mod', 'time' | |
@lineno = nil | |
end | |
def to_s | |
ret = "\n" | |
ret += TigerBehavior::prettystmts(self) | |
ret += "end\n" | |
return ret | |
end | |
end | |
---- inner | |
def parse(contents) | |
#alpha = /A-Za-z/ | |
#digit = /0-9/ | |
#alphanum = /A-Za-z0-9/ | |
@lineno = 1 if @lineno.nil? | |
@q = [] | |
for str in contents | |
until str.nil? or str.empty? | |
case str | |
when /^[ \t]/ | |
# ignore white space | |
when /^\n/ | |
@lineno += 1 | |
when /^\D+/ | |
name = $& | |
case str | |
when /^On/ | |
@q << [:ON, [$&, @lineno]] | |
when /^I/ | |
@q << [:I, [$&, @lineno]] | |
when /^my/ | |
@q << [:MY, [$&, @lineno]] | |
when /^for/ | |
@q << [:FOR, [$&, @lineno]] | |
when /^go/ | |
@q << [:GO, [$&, @lineno]] | |
when /^to/ | |
@q << [:TO, [$&, @lineno]] | |
when /^then/ | |
@q << [:THEN, [$&, @lineno]] | |
when /^the/ | |
@q << [:THE, [$&, @lineno]] | |
when /^leave/ | |
@q << [:LEAVE, [$&, @lineno]] | |
when /^come/ | |
@q << [:COME, [$&, @lineno]] | |
when /^back/ | |
@q << [:BACK, [$&, @lineno]] | |
when /^from/ | |
@q << [:FROM, [$&, @lineno]] | |
when /^wake/ | |
@q << [:WAKE, [$&, @lineno]] | |
when /^up/ | |
@q << [:UP, [$&, @lineno]] | |
when /^sleep/ | |
@q << [:SLEEP, [$&, @lineno]] | |
when /^do/ | |
@q << [:DO, [$&, @lineno]] | |
when /^not/ | |
@q << [:NOT, [$&, @lineno]] | |
when /^AM/ | |
@q << [:AM, [$&, @lineno]] | |
when /^PM/ | |
@q << [:PM, [$&, @lineno]] | |
when /^at/ | |
@q << [:AT, [$&, @lineno]] | |
when /^is/ | |
@q << [:IS, [$&, @lineno]] | |
when /^now/ | |
@q << [:NOW, [$&, @lineno]] | |
when /^low/ | |
@q << [:LOW, [$&, @lineno]] | |
when /^high/ | |
@q << [:HIGH, [$&, @lineno]] | |
when /^normal/ | |
@q << [:NORMAL, [$&, @lineno]] | |
when /^half/ | |
@q << [:HALF, [$&, @lineno]] | |
when /^an/ | |
@q << [:AN, [$&, @lineno]] | |
when /^hour/ | |
@q << [:HOUR, [$&, @lineno]] | |
when /^about/ | |
@q << [:ABOUT, [$&, @lineno]] | |
when /^around/ | |
@q << [:AROUND, [$&, @lineno]] | |
when /^just/ | |
@q << [:JUST, [$&, @lineno]] | |
when /^over/ | |
@q << [:OVER, [$&, @lineno]] | |
when /^under/ | |
@q << [:UNDER, [$&, @lineno]] | |
when /^no/ | |
@q << [:NO, [$&, @lineno]] | |
when /^than/ | |
@q << [:THAN, [$&, @lineno]] | |
when /^longer/ | |
@q << [:LONGER, [$&, @lineno]] | |
when /^shorter/ | |
@q << [:SHORTER, [$&, @lineno]] | |
when /^January/ | |
@q << [:JAN, [$&, @lineno]] | |
when /^February/ | |
@q << [:FEB, [$&, @lineno]] | |
when /^March/ | |
@q << [:MAR, [$&, @lineno]] | |
when /^April/ | |
@q << [:APR, [$&, @lineno]] | |
when /^May/ | |
@q << [:MAY, [$&, @lineno]] | |
when /^June/ | |
@q << [:JUNE, [$&, @lineno]] | |
when /^July/ | |
@q << [:JULY, [$&, @lineno]] | |
when /^August/ | |
@q << [:AUG, [$&, @lineno]] | |
when /^September/ | |
@q << [:SEPT, [$&, @lineno]] | |
when /^October/ | |
@q << [:OCT, [$&, @lineno]] | |
when /^November/ | |
@q << [:NOV, [$&, @lineno]] | |
when /^December/ | |
@q << [:DEC, [$&, @lineno]] | |
when /^minutes/ | |
@q << [:MINUTES, [$&, @lineno]] | |
when /^hours/ | |
@q << [:HOURS, [$&, @lineno]] | |
when /^seconds/ | |
@q << [:SECONDS, [$&, @lineno]] | |
when /^pulse/ | |
@q << [:PULSE, [$&, @lineno]] | |
when /^restlessness/ | |
@q << [:RESTLESSNESS, [$&, @lineno]] | |
when /^balance/ | |
@q << [:BALANCE, [$&, @lineno]] | |
when /^in/ | |
@q << [:IN, [$&, @lineno]] | |
when /^by/ | |
@q << [:BY, [$&, @lineno]] | |
when /^before/ | |
@q << [:BEFORE, [$&, @lineno]] | |
when /^after/ | |
@q << [:AFTER, [$&, @lineno]] | |
when /^earlier/ | |
@q << [:EARLIER, [$&, @lineno]] | |
when /^later/ | |
@q << [:LATER, [$&, @lineno]] | |
else #word | |
@q << [:WORD, [$&, @lineno]] | |
end | |
when /^\d/ | |
@q << [:NUMBER, [$&, @lineno]] | |
when /^\d{2}/ | |
@q << [:TWODIGIT, [$&, @lineno]] | |
when /^\d{4}/ | |
@q << [:FOURDIGIT, [$&, @lineno]] | |
when /^:/#/ | |
@q << [:COLON, [$&, @lineno]] | |
when /^,/ #/ | |
@q << [:COMMA, [$&, @lineno]] | |
else | |
puts "Illegal character \'#{str}\' on line ##{@lineno}\n" | |
end | |
str = $' | |
end | |
end | |
@q << [false, '$end'] | |
do_parse | |
end | |
def next_token | |
@q.shift | |
end | |
class << self | |
def prettystmts(p) | |
ret = "" | |
if p.nil? | |
return ret | |
end | |
case p.nodeTag | |
when :PROGRAM | |
ret += Toy::prettystmts(p.child1) | |
ret += "\n" | |
ret += Toy::prettystmts(p.child2) | |
when :STMTS | |
ret += Toy::prettystmts(p.child1) | |
ret += "\n" | |
if (p.next != nil) | |
ret += Toy::prettystmts(p.next) | |
end | |
when :DECLARE | |
ret += "declare " + p.nodeName | |
when :ASSIGN | |
ret += Toy::prettystmts(p.child1) | |
ret += " = " | |
ret += Toy::prettystmts(p.child2) | |
when :READ | |
ret += "read " | |
ret += Toy::prettystmts(p.child1) | |
when :WRITE | |
ret += "write " | |
ret += Toy::prettystmts(p.child1) | |
when :PLUS | |
ret += "(" | |
ret += Toy::prettystmts(p.child1) | |
ret += " + " | |
ret += Toy::prettystmts(p.child2) | |
ret += ")" | |
when :MINUS | |
ret += "(" | |
ret += Toy::prettystmts(p.child1) | |
ret += " - " | |
ret += Toy::prettystmts(p.child2) | |
ret += ")" | |
when :LIT | |
ret += p.nodeVal.to_s | |
when :ID | |
ret += p.nodeName.to_s | |
when :CALL | |
ret += "call #{p.nodeName}(" | |
ret += Toy::prettystmts(p.child1) | |
ret += ")" | |
when :DECLS | |
ret += Toy::prettystmts(p.child1) | |
ret += "\n" | |
if (p.next != nil) | |
ret += Toy::prettystmts(p.next) | |
end | |
when :PROCLIST | |
ret += Toy::prettystmts(p.child1) | |
ret += "\n" | |
if (p.next != nil) | |
ret += Toy::prettystmts(p.next) | |
end | |
when :PROCEDURE | |
ret += "proc #{p.nodeName} (" | |
ret += Toy::prettystmts(p.child1) | |
ret += ") \n" | |
ret += Toy::prettystmts(p.child2) | |
ret += Toy::prettystmts(p.next) | |
ret += "end\n" | |
when :VARLIST | |
ret += Toy::prettystmts(p.child1) | |
if (p.next != nil) | |
ret += ", " | |
ret += Toy::prettystmts(p.next) | |
end | |
when :ARGLIST | |
ret += Toy::prettystmts(p.child1) | |
if (p.next != nil) | |
ret += ", " | |
ret += Toy::prettystmts(p.next) | |
end | |
when :WHILE | |
ret += "while (" | |
ret += Toy::prettystmts(p.child1) | |
ret += ") \n" | |
ret += Toy::prettystmts(p.child2) | |
ret += "end\n" | |
when :IF | |
ret += "if (" | |
ret += Toy::prettystmts(p.child1) | |
ret += ") \n" | |
ret += Toy::prettystmts(p.child2) | |
ret += "end" | |
if (p.next != nil) | |
ret += Toy::prettystmts(p.next) | |
end | |
ret += "\n" | |
when :ELSE | |
ret += "else \n" | |
ret += Toy::prettystmts(p.child1) | |
ret += "end\n" | |
end | |
return ret | |
end | |
def wrap_parse(filename) | |
file = File.new(filename, "r") | |
if (file == nil) | |
puts(stderr, "Usage: ", file, " base_file_name") | |
exit(1) | |
end | |
parser = TigerBehavior.new | |
contents = file.readlines | |
root = parser.parse(contents) | |
return root | |
end | |
end | |
---- footer | |
#extra code | |
## Convert a string based time into a hash value | |
## | |
## @str string describing the time value "XhXmXs" | |
## | |
## @return hash of time { :hour, :minute, :seconds } | |
def parseTime(str) | |
time = {} | |
if str.match(/:/) | |
pieces = str.split(/[: ]/) | |
time['hour'] = pieces[0].to_i | |
time['minute'] = pieces[1].to_i | |
time['seconds'] = pieces[2].to_i | |
time['AMPM'] = pieces[3].to_s | |
else | |
pieces = str.split(' ') | |
for p in pieces | |
case p[-1..-1] | |
when 'h' then time['hour'] = p[0...-1].to_i | |
when 'm' then time['minute'] = p[0...-1].to_i | |
when 's' then time['seconds'] = p[0...-1].to_i | |
end | |
end | |
end | |
time | |
end | |
## Convert a time object into seconds | |
## | |
## @time hash depicting a time value from above | |
## | |
## @return the number of seconds into a day to the given time value | |
def timeToSeconds(time) | |
t = 0 | |
if time['AMPM'] | |
t += time['hour']*3600 unless time['hour'] == 12 | |
t += time['minute']*60 | |
t += time['seconds'] | |
t += 43200 if time['AMPM'] == 'PM' | |
else | |
t += time['hour']*3600 if time['hour'] | |
t += time['minute']*60 if time['minute'] | |
t += time['seconds'] if time['seconds'] | |
end | |
return t | |
end | |
## Convert seconds into a string | |
## | |
## @seconds fixnum value of seconds from above | |
## | |
## @return tring of hours, minutes and seconds | |
def secondsToString(seconds) | |
hours = seconds/3600 | |
minutes = (seconds/60)%60 | |
secs = seconds%60 | |
str = [] | |
str << hours.to_s+"h" unless hours.zero? | |
str << minutes.to_s+"m" unless minutes.zero? | |
str << secs.to_s+"s" unless secs.zero? | |
str.join(' ') | |
end | |
=begin | |
root = Tree.new() | |
if (argc != 2) | |
puts(stderr, "Usage: ", ARGV[1], " base_file_name") | |
exit(1) | |
end | |
base = argv[1] | |
root = yyparse | |
pretty(root) | |
=end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment