Author: pmichaud
Date: Wed Oct 26 14:58:07 2005
New Revision: 9583
Modified:
trunk/compilers/pge/PGE/OPTable.pir
trunk/compilers/pge/demo.pir
Log:
Modified calling interface, added ternary: class.
Modified: trunk/compilers/pge/PGE/OPTable.pir
==============================================================================
--- trunk/compilers/pge/PGE/OPTable.pir (original)
+++ trunk/compilers/pge/PGE/OPTable.pir Wed Oct 26 14:58:07 2005
@@ -11,13 +11,15 @@ method to add operator tokens into the t
.local pmc optable, digit
$I0 = find_type "PGE::OPTable"
+ optable = new $I0
+
digit = find_global "PGE::Rule", "digit"
- optable."addtok"(" infix:+", "PGE::Match")
- optable."addtok"(" infix:-", "PGE::Match", "infix:+")
- optable."addtok"(" infix:*", "PGE::Match", ">infix:+")
- optable."addtok"(" infix:/", "PGE::Match", "infix:*")
- optable."addtok"(" term:", digit, ">infix:*")
- optable."addtok"(" circumfix:( )", "PGE::Match", "term:")
+ optable."addtok"("infix:+")
+ optable."addtok"("infix:-", "infix:+")
+ optable."addtok"("infix:*", ">infix:+")
+ optable."addtok"("infix:/", "infix:*")
+ optable."addtok"("term:", ">infix:*", digit)
+ optable."addtok"("circumfix:( )", "term:")
The C<parse> method can then be used to obtain a Match object
representing the parse of a string:
@@ -39,13 +41,15 @@ subroutine that calls the parser:
.namespace [ "PGE::OPTable" ]
-.const int PGE_OPTABLE_CLOSE = 0
+.const int PGE_OPTABLE_EMPTY = 0
.const int PGE_OPTABLE_TERM = 1
.const int PGE_OPTABLE_POSTFIX = 2
-.const int PGE_OPTABLE_PREFIX = 3
-.const int PGE_OPTABLE_INFIX = 4
-.const int PGE_OPTABLE_CIRCUMFIX = 5
-.const int PGE_OPTABLE_POSTCIRCUMFIX = 6
+.const int PGE_OPTABLE_CLOSE = 3
+.const int PGE_OPTABLE_PREFIX = 4
+.const int PGE_OPTABLE_INFIX = 5
+.const int PGE_OPTABLE_TERNARY = 6
+.const int PGE_OPTABLE_POSTCIRCUMFIX = 7
+.const int PGE_OPTABLE_CIRCUMFIX = 8
.include "cclass.pasm"
@@ -53,7 +57,7 @@ subroutine that calls the parser:
=item C<__onload()>
-Creates the PGE::OPTable and PGE::Op classes.
+Creates the PGE::OPTable class.
=cut
@@ -65,8 +69,6 @@ Creates the PGE::OPTable and PGE::Op cla
addattribute base, "%:opertable"
addattribute base, "%:wstermtable"
addattribute base, "%:wsopertable"
- $P0 = getclass "PGE::Match"
- $P0 = subclass $P0, "PGE::Op"
.end
=item C<__init()>
@@ -91,7 +93,7 @@ Initializes a PGE::OPTable object.
=head2 Methods
-=item C<addtok(STR name, PMC match, STR rel, STR opts)>
+=item C<addtok(STR name [, STR rel [, PMC match [, STR opts]]])>
Adds a new token to the operator precedence table. Operators are
named as strings representing the syntactic category of the operator
@@ -99,31 +101,34 @@ and the operator token(s). Available sy
"infix:", "prefix:", "postfix:", "term:", "circumfix:", and
"postcircumfix:".
+The C<rel> argument specifies the precedence of the new operator
+relative to an existing operator, with a leading "<" or ">" indicating
+looser or tighter precedence.
+
The C<match> argument is either a string identifying the class of
Match object to create for this operator, or a (rule) subroutine
to be called that will parse the complete token and return an
-appropriate match object.
+appropriate match object. The default for C<match> is "PGE::Match".
-The C<rel> argument specifies the precedence of this operator
-relative to another operator, with a leading ">" or "<" used to indicate
-tighter or looser precedence. Finally, the C<opts> parameter
-can be used to indicate the associativity of the operator ("left" or
-"right").
+Finally, the C<opts> parameter can be used to indicate
+the associativity of the operator ("left" or "right") and whether
+the token disallows leading whitespace ("nows").
=cut
.sub "addtok" :method
.param string name
- .param pmc match
.param string rel :optional
.param int has_rel :opt_flag
+ .param pmc match :optional
+ .param int has_match :opt_flag
.param string opts :optional
.param int has_opts :opt_flag
.local string equiv, syncat
.local pmc toktable, termtable, wstermtable, opertable, wsopertable
.local pmc tok
.local string tok1, tok2
- .local int isws
+ .local int nows
toktable = getattribute self, "PGE::OPTable\x0%:toktable"
termtable = getattribute self, "PGE::OPTable\x0%:termtable"
@@ -131,32 +136,35 @@ can be used to indicate the associativit
wstermtable = getattribute self, "PGE::OPTable\x0%:wstermtable"
wsopertable = getattribute self, "PGE::OPTable\x0%:wsopertable"
- if has_opts goto addtok_1
+ if has_opts goto set_equiv
opts = "left"
- addtok_1:
+ if has_match goto set_equiv
+ match = new String
+ match = "PGE::Match"
+
+ set_equiv:
equiv = "="
- if has_rel == 0 goto addtok_2
+ if has_rel == 0 goto set_nows
$S0 = substr rel, 0, 1
$I0 = index "=<>", $S0
- if $I0 == -1 goto addtok_3
+ if $I0 == -1 goto set_equiv_1
$S1 = substr rel, 1
$P0 = toktable[$S1]
equiv = $P0['equiv']
equiv = clone equiv
substr equiv, -1, 0, $S0
- goto addtok_2
- addtok_3:
+ goto set_nows
+ set_equiv_1:
$P0 = toktable[rel]
equiv = $P0['equiv']
- addtok_2:
- isws = 0
- $S0 = substr name, 0, 1
- if $S0 != " " goto addtok_4
- isws = 1
- name = substr name, 1
+ set_nows:
+ nows = 0
+ $I0 = index opts, "nows"
+ if $I0 < 0 goto addtok_1
+ nows = 1
- addtok_4:
+ addtok_1:
tok = new Hash
tok["name"] = name
tok["opts"] = opts
@@ -168,7 +176,7 @@ can be used to indicate the associativit
syncat = substr name, 0, $I0
tok1 = substr name, $I0
$I0 = index tok1, " "
- if $I0 < 0 goto addtok_5
+ if $I0 < 0 goto addtok_2
$I1 = $I0 + 1
tok2 = substr tok1, $I1
tok1 = substr tok1, 0, $I0
@@ -177,7 +185,7 @@ can be used to indicate the associativit
$P0["syncat"] = PGE_OPTABLE_CLOSE
opertable[tok2] = $P0
wsopertable[tok2] = $P0
- addtok_5:
+ addtok_2:
tok["tok1"] = tok1
toktable[name] = tok
if syncat == "infix:" goto infix
@@ -185,6 +193,7 @@ can be used to indicate the associativit
if syncat == "circumfix:" goto circumfix
if syncat == "prefix:" goto prefix
if syncat == "postcircumfix:" goto postcircumfix
+ if syncat == "ternary:" goto ternary
term:
tok["syncat"] = PGE_OPTABLE_TERM
goto expect_term
@@ -205,14 +214,18 @@ can be used to indicate the associativit
tok["syncat"] = PGE_OPTABLE_POSTCIRCUMFIX
tok["arity"] = 2
goto expect_op
+ ternary:
+ tok["syncat"] = PGE_OPTABLE_TERNARY
+ tok["arity"] = 3
+ goto expect_op
expect_term:
termtable[tok1] = tok
- if isws == 0 goto end
+ if nows goto end
wstermtable[tok1] = tok
goto end
expect_op:
opertable[tok1] = tok
- if isws == 0 goto end
+ if nows goto end
wsopertable[tok1] = tok
end:
.end
@@ -232,6 +245,7 @@ representing the result of the parse.
.local pmc termtable, opertable, wstermtable, wsopertable
.local pmc oper
.local pmc tok, match, top
+ .local int tokcat, topcat
.local pmc termstack, operstack, tokstack
.local int arity
.local pmc args
@@ -266,8 +280,8 @@ representing the result of the parse.
bsr tok_match
unless oper goto term_error
$P0 = tok["syncat"]
- if $P0 == PGE_OPTABLE_PREFIX goto oper_shift
- if $P0 == PGE_OPTABLE_CIRCUMFIX goto oper_shift
+ if $P0 == PGE_OPTABLE_PREFIX goto oper_shift # (S1)
+ if $P0 == PGE_OPTABLE_CIRCUMFIX goto oper_shift # (S2, P2)
push termstack, oper
pos = oper.to()
@@ -278,37 +292,52 @@ representing the result of the parse.
$P0 = opertable
expect_oper_1:
key = $P0."lkey"(target, wspos)
- if key == "" goto end
+ $I0 = exists $P0[key]
+ if $I0 == 0 goto end
tok = $P0[key]
bsr tok_match
unless oper goto end
+ tokcat = tok["syncat"]
expect_oper_2:
+ topcat = PGE_OPTABLE_EMPTY
$I0 = elements tokstack
- if $I0 < 1 goto oper_shift
+ if $I0 > 0 goto expect_oper_3
+ if tokcat == PGE_OPTABLE_CLOSE goto end # (E3)
+ goto oper_shift # (S3)
+ expect_oper_3:
top = tokstack[-1]
- $P0 = top["syncat"]
- if $P0 <= PGE_OPTABLE_POSTFIX goto oper_reduce
- if $P0 >= PGE_OPTABLE_CIRCUMFIX goto oper_shift
- $P0 = tok["syncat"]
- if $P0 == PGE_OPTABLE_CLOSE goto oper_reduce
- $P0 = tok["equiv"]
+ 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)
+ $P0 = tok["equiv"]
$P1 = top["equiv"]
- if $P1 < $P0 goto oper_shift
- if $P1 > $P0 goto oper_reduce
+ if $P0 > $P1 goto oper_shift # (P)
+ if topcat != PGE_OPTABLE_TERNARY goto expect_oper_4
+ if tokcat != PGE_OPTABLE_TERNARY goto ternary_error # (P/E)
+ goto oper_shift # (S7)
+ expect_oper_4:
+ if $P1 < $P0 goto oper_reduce # (P)
$S0 = top["opts"]
- $I0 = index $S0, "right"
- if $I0 >= 0 goto oper_shift
+ $I0 = index $S0, "right"
+ if $I0 >= 0 goto oper_shift # (P/A)
oper_reduce:
bsr reduce
goto expect_oper_2
+ oper_close:
+ if topcat < PGE_OPTABLE_TERNARY goto oper_reduce # (R5)
+ $P1 = top["tok2"]
+ $S0 = $P1
+ if key != $S0 goto end # (C5)
oper_shift:
push tokstack, tok
push operstack, oper
pos = oper.to()
- $P0 = tok["syncat"]
- if $P0 >= PGE_OPTABLE_PREFIX goto expect_term
+ tokcat = tok["syncat"]
+ 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
- oper_close:
reduce:
$P0 = pop tokstack
@@ -323,9 +352,9 @@ representing the result of the parse.
$P0["args"] = args
reduce_args:
if arity < 1 goto reduce_end
+ dec arity
$P1 = pop termstack
unshift args, $P1
- dec arity
goto reduce_args
reduce_end:
push termstack, $P0
@@ -347,7 +376,7 @@ representing the result of the parse.
tok_match_end:
$P0 = tok["name"]
$P0 = clone $P0
- oper["name"] = $P0
+ oper["type"] = $P0
ret
end:
@@ -371,6 +400,71 @@ representing the result of the parse.
throw $P0
mobpos = -1
.return (mob)
+
+ ternary_error:
+ $P0 = new Exception
+ $S0 = "Missing ternary close at offset "
+ $S1 = wspos
+ $S0 .= $S1
+ $S0 .= "\n"
+ $P0["_message"] = $S0
+ throw $P0
+ mobpos = -1
+ .return (mob)
.end
+=head1 Miscellaneous Notes
+
+Here's the shift-reduce table used by the C<parse> method.
+The digits in the table map each state to the corresponding
+statement in the C<parse> method above.
+
+ tokstack Current token
+ -------- ---------------------------------------------------------
+ postfix close prefix infix ternary postcirc circfix
+ empty S3 E3 S1 S3 S3 S3 S2
+ postfix R4 R4 X R4 R4 R4 X
+ close P R5 S1 P P P P2 (*)
+ prefix P R5 S1 P P P S2
+ infix P R5 S1 P/A P P S2
+ ternary P/E C5 S1 P/E S7 P/E S2
+ postcirc S6 C5 S1 S6 S6 S6 S2
+ circfix S6 C5 S1 S6 S6 S6 S2
+
+ Expect oper mixed term term term term term
+
+ Legend:
+ S# = shift -- push operator onto token stack
+ R# = reduce -- pop operator from token stack, and fill it with
+ the appropriate number of arguments (arity) from the term stack.
+ Then put the operator token onto the term stack. Reducing a
+ close token requires popping two operators from the token
+ stack. Reducing a lone ternary operator is a parse error
+ (its close token must be present).
+ P = precedence -- compare the relative precedence of the top
+ token in the token stack with the current token.
+ If current is tighter than top, shift.
+ If current is looser than top, reduce.
+ P/A = precedence with associativity -- for tokens with equal
+ precedence, use the associativity of the top token in the
+ token stack, shift if it's right associative, reduce otherwise.
+ P/E = higher precedence only -- shift if the current token has
+ higher precedence than the top token on the stack, otherwise
+ it's a parse error.
+ C = close -- If the current token is an appropriate closing
+ token for the top operator on the token stack, then shift.
+ Otherwise, it's an unbalanced closing token.
+ X = unreachable combination
+ E = either the end of the parse, or a parse error (probably
+ to be determined by the caller)
+
+ (*) - XXX: The current implementation assumes that circumfix
+ operators are always tighter than any close, and so performs a shift.
+
+=head1 AUTHOR
+
+Patrick Michaud ([EMAIL PROTECTED]) is the author and maintainer.
+Patches and suggestions should be sent to the Perl 6 compiler list
+([email protected]).
+=cut
Modified: trunk/compilers/pge/demo.pir
==============================================================================
--- trunk/compilers/pge/demo.pir (original)
+++ trunk/compilers/pge/demo.pir Wed Oct 26 14:58:07 2005
@@ -14,6 +14,7 @@
.local string gname
load_bytecode "PGE.pbc"
+ load_bytecode "dumper.imc"
load_bytecode "PGE/Dumper.pir"
load_bytecode "PGE/Glob.pir"
load_bytecode "PGE/Text.pir"
@@ -51,7 +52,8 @@
match_result:
unless match goto match_fail
print "match succeeded\n"
- match."dump"("$/")
+ $P0 = find_global "_dumper"
+ $P0(match, "$/")
goto read_loop
match_fail:
print "match failed\n"