Skip to content

Instantly share code, notes, and snippets.

@ChadyG
Created July 18, 2010 07:06
Show Gist options
  • Save ChadyG/480195 to your computer and use it in GitHub Desktop.
Save ChadyG/480195 to your computer and use it in GitHub Desktop.
#
# 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