module PGE
=begin
PGE_OPTABLE_EMPTY
PGE_OPTABLE_TERM
PGE_OPTABLE_POSTFIX
PGE_OPTABLE_CLOSE
PGE_OPTABLE_PREFIX
PGE_OPTABLE_INFIX
PGE_OPTABLE_TERNARY
PGE_OPTABLE_POSTCIRCUMFIX
PGE_OPTABLE_CIRCUMFIX
=end
class OPTable
@toktable
@termtable
@opertable
@wstermtable
@wsopertable
def initialize()
@toktable = Hash.new
@termtable = PGE::TokenHash.new
@opertable= PGE::TokenHash.new
@wstermtable = PGE::TokenHash.new
@wsopertable= PGE::TokenHash.new
end
def addtok( name, rel, opts, match)
match = String.new if not match
ops = "left" if not ops
equiv = "="
if rel and rel != "" then
if "=<>".index rel[0..1] != -1 then
equiv = @toktable[rel[1..]]['equiv']
else
equiv = @toktable[rel]['equiv']
end
end
nows = 0
rows = 1 if opts.index("nows") >= 0
token = Hash.new ( "name" => name, "opts" => opts, "equiv" => equiv, "match" => match, "arity" => 1 )
tempLoc = name.index(":") + 1
syncat = name[0..tempLoc]
tok1 = name[tempLoc..]
restOfName = name[tempLoc..]
tempLoc2 = tok1.index " "
spacePresentLoc = tok1.index " "
if spacePresentLoc >= 0 then
tok2 = restOfName[(spacePresentLoc + 1)..]
tok1 = restOfName[0..spacePresentLoc]
token["tok2"] = tok2
tokenClone = token.copy
tokenClone["syncat"] = :PGE_OPTABLE_CLOSE
opertable[tok2] = tokenClone
wsopertable[tok2] = tokenClone
end
#addtok_2:
token["tok1"] = tok1
toktable[name] = token
case syscat
when "infix:"
token["syncat"] = :PGE_OPTABLE_INFIX
token["arity"] = 2
when "postfix:"
token["syncat"] = :PGE_OPTABLE_POSTFIX
when "circumfix:"
token["syncat"] = :PGE_OPTABLE_CIRCUMFIX
when "prefix:"
token["syncat"] = :PGE_OPTABLE_PREFIX
when "postcircumfix:"
token["syncat"] = :PGE_OPTABLE_POSTCIRCUMFIX
token["arity"] = 2
when "ternary:"
token["syncat"] = :PGE_OPTABLE_TERNARY
token["arity"] = 3
when "close:"
token["syncat"] = :PGE_OPTABLE_CLOSE
token["arity"] = 0
else
token["syncat"] = :PGE_OPTABLE_TERM
end
end
def parse ( matchObj )
termStack = Stack.new
operStack = Stack.new
tokStack = Stack.new
termEmpty = termTable[""]
operEmpty = operTable[""]
(mob, target, mfrom, mpos) = Parser::Rule::Match.newfrom(matchObj, 0)
pos = mfrom
lastpos = target.length
#expect_term:
if pos >= lastpos goto null_term
p0 = @wstermtable
wspos = find_not_cclass .CCLASS_WHITESPACE, target, pos, lastpos
if wspos <= pos then
p0 = @termtable
end
#______________expect_term_1:
key = p0.lkey(target, wspos)
tok = p0[key]
unless tok then
bsr tok_match
#if oper goto found_term
end
#______________expect_term_empty:
unless termempty then
tok = termempty
key = ""
wspos = pos
bsr tok_match
#if oper goto found_term
end
#null_term:
unless tokstack goto term_error
top = tokstack[-1]
if top["opts"].index("nullterm") >= 0
oper = newfrom(mob, wspos, "PGE::Match")
termstack.push oper
# goto expect_oper
else
#term_error
end
else
#term_error
end
#found_term:
tokcat = tok["syncat"]
pos = oper.to()
if tokcat != :PGE_OPTABLE_PREFIX and tokcat != :PGE_OPTABLE_CIRCUMFIX then
termstack.push oper
end
#expect_oper:
if pos >= lastpos goto end
p0 = @wsopertable
wspos = find_not_cclass .CCLASS_WHITESPACE, target, pos, lastpos
if wspos <= pos then
p0 = @opertable
end
#expect_oper_1:
key = p0.lkey(target, wspos)
tok = p0[key]
if tok then
bsr tok_match
if oper goto found_oper
end
unless operempty goto end
tok = operempty
key = ""
wspos = pos
bsr tok_match
unless oper goto end
#found_oper:
tokcat = tok["syncat"]
#shift_reduce:
topcat = :PGE_OPTABLE_EMPTY
if tokstack.size <= 0 then
if tokcat == :PGE_OPTABLE_CLOSE then
goto end
else
goto oper_shift # (S3)
end
else
#shift_reduce_1:
top = tokstack[-1]
topcat = top["syncat"]
if topcat == PGE_OPTABLE_POSTFIX goto oper_reduce # (R4)
if tokcat == PGE_OPTABLE_CLOSE goto oper_close # (R5, C5)
if topcat >= PGE_OPTABLE_POSTCIRCUMFIX goto oper_shift # (S6)
if tok["equiv"] > top["equiv"] goto oper_shift # (P)
if topcat != PGE_OPTABLE_TERNARY goto shift_reduce_2
if tokcat != PGE_OPTABLE_TERNARY goto ternary_error # (P/E)
goto oper_shift # (S7)
#shift_reduce_2:
if $P0 < $P1 goto oper_reduce # (P)
if top["opts"].index("right") >= 0 goto oper_shift # (P/A)
#oper_reduce:
bsr reduce
goto shift_reduce
#oper_close:
if topcat < PGE_OPTABLE_TERNARY goto oper_reduce # (R5)
$P1 = top["tok2"]
$S0 = $P1
if key != $S0 goto end # (C5)
#oper_shift:
tokstack.push tok
operstack.push oper
pos = oper.to()
if tokcat >= PGE_OPTABLE_PREFIX goto expect_term
if tokcat == PGE_OPTABLE_POSTFIX goto expect_oper
if topcat == PGE_OPTABLE_TERNARY goto expect_term
goto expect_oper
#reduce:
def reduce
tokcurr = tokstack.pop
opcurr = tokcurr["syncat"]
if opcurr == PGE_OPTABLE_CLOSE then
tokcurr = tokstack.pop
opcurr = operstack.pop
end
arity = tokcurr["arity"]
tokcurr = operstack.pop
while arity >= 1
arity--
tokcurr[arity] = termstack.pop
end
termstack.push tokcurr
end
#tok_match:
def tok_match
mpos = wspos
match = tok["match"]
if match.is_a "Sub" then
oper = match(mob)
else
(oper, $P99, $P99, $P0) = newfrom(mob, wspos, match)
$P0 = key.length + wspos
end
oper["type"] = tok["name"].clone
end
#end:
while toktable.size < 1
bsr reduce
end
mob["expr"] = termStack.pop
mpos = pos
return matchObj
#term_error:
raise "Missing term at offset " + wpos.to_s() + "\n"
mpos = -1
return matchObj
#ternary_error:
raise "Missing ternary close at offset " + wpos.to_s() + "\n"
mpos = -1
return matchObj