Author: pmichaud
Date: Tue Oct 25 23:55:38 2005
New Revision: 9573
Added:
trunk/compilers/pge/PGE/OPTable.pir
Modified:
trunk/MANIFEST
trunk/compilers/pge/PGE.pir
trunk/compilers/pge/PGE/Match.pir
trunk/config/gen/makefiles/pge.in
trunk/lib/Parrot/Test/PGE.pm
trunk/runtime/parrot/library/PGE/Dumper.pir
Log:
Added PGE::OPTable (shift+reduce parsing w/operator precedence) and
moved dumper functions to PGE/Dumper.pir .
Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST (original)
+++ trunk/MANIFEST Tue Oct 25 23:55:38 2005
@@ -141,6 +141,7 @@ compilers/pge/mklib.pir
compilers/pge/PGE.pir []
compilers/pge/PGE/Exp.pir []
compilers/pge/PGE/Match.pir []
+compilers/pge/PGE/OPTable.pir []
compilers/pge/PGE/P6Rule.pir []
compilers/pge/PGE/Rule.pir []
compilers/pge/PGE/TokenHash.pir []
Modified: trunk/compilers/pge/PGE.pir
==============================================================================
--- trunk/compilers/pge/PGE.pir (original)
+++ trunk/compilers/pge/PGE.pir Tue Oct 25 23:55:38 2005
@@ -28,6 +28,8 @@ defined.
load()
load = find_global "PGE::Rule", "__onload"
load()
+ load = find_global "PGE::OPTable", "__onload"
+ load()
.end
.include "compilers/pge/PGE/TokenHash.pir"
@@ -36,3 +38,4 @@ defined.
.include "compilers/pge/PGE/Rule.pir"
.include "compilers/pge/PGE/P6Rule.pir"
.include "compilers/pge/PGE/Library.pir"
+.include "compilers/pge/PGE/OPTable.pir"
Modified: trunk/compilers/pge/PGE/Match.pir
==============================================================================
--- trunk/compilers/pge/PGE/Match.pir (original)
+++ trunk/compilers/pge/PGE/Match.pir Tue Oct 25 23:55:38 2005
@@ -303,104 +303,6 @@ Returns the array component of the match
.return (array)
.end
-=item C<dump()>
-
-Produces a data dump of the match object and all of its subcaptures.
-
-=cut
-
-.sub "dump" method
- .param string prefix :optional # name of match variable
- .param int has_prefix :opt_flag
- .param string b1 :optional # bracket open
- .param int has_b1 :opt_flag
- .param string b2 :optional # bracket close
- .param int has_b2 :opt_flag
-
- .local pmc capt
- .local int spi, spc
- .local pmc iter
- .local string prefix1, prefix2
-
- if has_b2 goto start
- b2 = "]"
- if has_b1 goto start
- b1 = "["
- start:
- print prefix
- print ":"
- unless self goto subpats
- print " <"
- print self
- print " @ "
- $I0 = self."from"()
- print $I0
- print "> "
-
- subpats:
- $I0 = self
- print $I0
- print "\n"
- capt = getattribute self, "PGE::Match\x0@:capt"
- if_null capt, subrules
- spi = 0
- spc = elements capt
- subpats_1:
- unless spi < spc goto subrules
- prefix1 = concat prefix, b1
- $S0 = spi
- concat prefix1, $S0
- concat prefix1, b2
- $I0 = defined capt[spi]
- unless $I0 goto subpats_2
- $P0 = capt[spi]
- bsr dumper
- subpats_2:
- inc spi
- goto subpats_1
-
- subrules:
- capt = getattribute self, "PGE::Match\x0%:capt"
- if_null capt, end
- iter = new Iterator, capt
- iter = 0
- subrules_1:
- unless iter goto end
- $S0 = shift iter
- prefix1 = concat prefix, "<"
- concat prefix1, $S0
- concat prefix1, ">"
- $I0 = defined capt[$S0]
- unless $I0 goto subrules_1
- $P0 = capt[$S0]
- bsr dumper
- goto subrules_1
-
- dumper:
- $I0 = isa $P0, "Array"
- if $I0 goto dumper_0
- $P0."dump"(prefix1, b1, b2)
- ret
- dumper_0:
- $I0 = 0
- $I1 = elements $P0
- dumper_1:
- if $I0 >= $I1 goto dumper_2
- $P1 = $P0[$I0]
- prefix2 = concat prefix1, b1
- $S0 = $I0
- concat prefix2, $S0
- concat prefix2, b2
- $P1."dump"(prefix2, b1, b2)
- inc $I0
- goto dumper_1
- dumper_2:
- ret
-
- end:
- .return ()
-.end
-
=head1 AUTHOR
Patrick Michaud ([EMAIL PROTECTED]) is the author and maintainer.
Added: trunk/compilers/pge/PGE/OPTable.pir
==============================================================================
--- (empty file)
+++ trunk/compilers/pge/PGE/OPTable.pir Tue Oct 25 23:55:38 2005
@@ -0,0 +1,376 @@
+=head1 Title
+
+PGE::OPTable - PGE operator precedence table and parser
+
+=head1 DESCRIPTION
+
+This file implements the operator precedence table used to perform
+shift/reduce parsing of strings. To get a parser, first create an
+instance of C<PGE::OPTable>, then make calls to the C<addtok>
+method to add operator tokens into the table:
+
+ .local pmc optable, digit
+ $I0 = find_type "PGE::OPTable"
+ 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:")
+
+The C<parse> method can then be used to obtain a Match object
+representing the parse of a string:
+
+ $P0 = optable."parse"("1 + 2 * 3")
+
+To make a parser callable from a rule, create a custom rule
+subroutine that calls the parser:
+
+ .sub "expr"
+ .param pmc mob
+ .local pmc optable
+ optable = find_name "optable"
+ $P0 = optable."parse"(mob)
+ .return ($P0)
+ .end
+
+=cut
+
+.namespace [ "PGE::OPTable" ]
+
+.const int PGE_OPTABLE_CLOSE = 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
+
+.include "cclass.pasm"
+
+=head1 Methods
+
+=item C<__onload()>
+
+Creates the PGE::OPTable and PGE::Op classes.
+
+=cut
+
+.sub "__onload"
+ .local pmc base
+ base = newclass "PGE::OPTable"
+ addattribute base, "%:toktable"
+ addattribute base, "%:termtable"
+ addattribute base, "%:opertable"
+ addattribute base, "%:wstermtable"
+ addattribute base, "%:wsopertable"
+ $P0 = getclass "PGE::Match"
+ $P0 = subclass $P0, "PGE::Op"
+.end
+
+=item C<__init()>
+
+Initializes a PGE::OPTable object.
+
+=cut
+
+.sub "__init" :method
+ $P0 = new Hash
+ setattribute self, "PGE::OPTable\x0%:toktable", $P0
+ $I0 = find_type "PGE::TokenHash"
+ $P0 = new $I0
+ setattribute self, "PGE::OPTable\x0%:termtable", $P0
+ $P0 = new $I0
+ setattribute self, "PGE::OPTable\x0%:wstermtable", $P0
+ $P0 = new $I0
+ setattribute self, "PGE::OPTable\x0%:opertable", $P0
+ $P0 = new $I0
+ setattribute self, "PGE::OPTable\x0%:wsopertable", $P0
+.end
+
+=head2 Methods
+
+=item C<addtok(STR name, PMC match, STR rel, STR opts)>
+
+Adds a new token to the operator precedence table. Operators are
+named as strings representing the syntactic category of the operator
+and the operator token(s). Available syntactic categories include
+"infix:", "prefix:", "postfix:", "term:", "circumfix:", and
+"postcircumfix:".
+
+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.
+
+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").
+
+=cut
+
+.sub "addtok" :method
+ .param string name
+ .param pmc match
+ .param string rel :optional
+ .param int has_rel :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
+
+ toktable = getattribute self, "PGE::OPTable\x0%:toktable"
+ termtable = getattribute self, "PGE::OPTable\x0%:termtable"
+ opertable = getattribute self, "PGE::OPTable\x0%:opertable"
+ wstermtable = getattribute self, "PGE::OPTable\x0%:wstermtable"
+ wsopertable = getattribute self, "PGE::OPTable\x0%:wsopertable"
+
+ if has_opts goto addtok_1
+ opts = "left"
+ addtok_1:
+ equiv = "="
+ if has_rel == 0 goto addtok_2
+ $S0 = substr rel, 0, 1
+ $I0 = index "=<>", $S0
+ if $I0 == -1 goto addtok_3
+ $S1 = substr rel, 1
+ $P0 = toktable[$S1]
+ equiv = $P0['equiv']
+ equiv = clone equiv
+ substr equiv, -1, 0, $S0
+ goto addtok_2
+ addtok_3:
+ $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
+
+ addtok_4:
+ tok = new Hash
+ tok["name"] = name
+ tok["opts"] = opts
+ tok["equiv"] = equiv
+ tok["match"] = match
+ tok["arity"] = 1
+ $I0 = index name, ":"
+ inc $I0
+ syncat = substr name, 0, $I0
+ tok1 = substr name, $I0
+ $I0 = index tok1, " "
+ if $I0 < 0 goto addtok_5
+ $I1 = $I0 + 1
+ tok2 = substr tok1, $I1
+ tok1 = substr tok1, 0, $I0
+ tok["tok2"] = tok2
+ $P0 = clone tok
+ $P0["syncat"] = PGE_OPTABLE_CLOSE
+ opertable[tok2] = $P0
+ wsopertable[tok2] = $P0
+ addtok_5:
+ tok["tok1"] = tok1
+ toktable[name] = tok
+ if syncat == "infix:" goto infix
+ if syncat == "postfix:" goto postfix
+ if syncat == "circumfix:" goto circumfix
+ if syncat == "prefix:" goto prefix
+ if syncat == "postcircumfix:" goto postcircumfix
+ term:
+ tok["syncat"] = PGE_OPTABLE_TERM
+ goto expect_term
+ infix:
+ tok["syncat"] = PGE_OPTABLE_INFIX
+ tok["arity"] = 2
+ goto expect_op
+ prefix:
+ tok["syncat"] = PGE_OPTABLE_PREFIX
+ goto expect_term
+ postfix:
+ tok["syncat"] = PGE_OPTABLE_POSTFIX
+ goto expect_op
+ circumfix:
+ tok["syncat"] = PGE_OPTABLE_CIRCUMFIX
+ goto expect_term
+ postcircumfix:
+ tok["syncat"] = PGE_OPTABLE_POSTCIRCUMFIX
+ tok["arity"] = 2
+ goto expect_op
+ expect_term:
+ termtable[tok1] = tok
+ if isws == 0 goto end
+ wstermtable[tok1] = tok
+ goto end
+ expect_op:
+ opertable[tok1] = tok
+ if isws == 0 goto end
+ wsopertable[tok1] = tok
+ end:
+.end
+
+=item C<parse(PMC mob)>
+
+Parse the string or match given by C<mob>, and return a Match object
+representing the result of the parse.
+
+=cut
+
+.sub "parse" :method
+ .param pmc mob
+ .local string target
+ .local int pos, lastpos, wspos
+ .local pmc mobpos
+ .local pmc termtable, opertable, wstermtable, wsopertable
+ .local pmc oper
+ .local pmc tok, match, top
+ .local pmc termstack, operstack, tokstack
+ .local int arity
+ .local pmc args
+ .local string key
+ .local pmc newfrom
+
+ termtable = getattribute self, "PGE::OPTable\x0%:termtable"
+ opertable = getattribute self, "PGE::OPTable\x0%:opertable"
+ wstermtable = getattribute self, "PGE::OPTable\x0%:wstermtable"
+ wsopertable = getattribute self, "PGE::OPTable\x0%:wsopertable"
+ termstack = new PerlArray
+ operstack = new PerlArray
+ tokstack = new PerlArray
+
+ newfrom = find_global "PGE::Match", "newfrom"
+ mob = newfrom(mob, 0)
+ $P0 = getattribute mob, "PGE::Match\x0$:from"
+ pos = $P0
+ $P0 = getattribute mob, "PGE::Match\x0$:target"
+ mobpos = getattribute mob, "PGE::Match\x0$:pos"
+ target = $P0
+ lastpos = length target
+
+ expect_term:
+ $P0 = wstermtable
+ wspos = find_not_cclass .CCLASS_WHITESPACE, target, pos, lastpos
+ if wspos > pos goto expect_term_1
+ $P0 = termtable
+ expect_term_1:
+ key = $P0."lkey"(target, wspos)
+ tok = $P0[key]
+ 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
+ push termstack, oper
+ pos = oper.to()
+
+ expect_oper:
+ $P0 = wsopertable
+ wspos = find_not_cclass .CCLASS_WHITESPACE, target, pos, lastpos
+ if wspos > pos goto expect_oper_1
+ $P0 = opertable
+ expect_oper_1:
+ key = $P0."lkey"(target, wspos)
+ if key == "" goto end
+ tok = $P0[key]
+ bsr tok_match
+ unless oper goto end
+ expect_oper_2:
+ $I0 = elements tokstack
+ if $I0 < 1 goto oper_shift
+ 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"]
+ $P1 = top["equiv"]
+ if $P1 < $P0 goto oper_shift
+ if $P1 > $P0 goto oper_reduce
+ $S0 = top["opts"]
+ $I0 = index $S0, "right"
+ if $I0 >= 0 goto oper_shift
+ oper_reduce:
+ bsr reduce
+ goto expect_oper_2
+ oper_shift:
+ push tokstack, tok
+ push operstack, oper
+ pos = oper.to()
+ $P0 = tok["syncat"]
+ if $P0 >= PGE_OPTABLE_PREFIX goto expect_term
+ goto expect_oper
+ oper_close:
+
+ reduce:
+ $P0 = pop tokstack
+ $P1 = $P0["syncat"]
+ if $P1 != PGE_OPTABLE_CLOSE goto reduce_1
+ $P0 = pop tokstack
+ $P1 = pop operstack
+ reduce_1:
+ arity = $P0["arity"]
+ $P0 = pop operstack
+ args = new PerlArray
+ $P0["args"] = args
+ reduce_args:
+ if arity < 1 goto reduce_end
+ $P1 = pop termstack
+ unshift args, $P1
+ dec arity
+ goto reduce_args
+ reduce_end:
+ push termstack, $P0
+ ret
+
+ tok_match:
+ mobpos = wspos
+ match = tok["match"]
+ $I0 = isa match, "Sub"
+ if $I0 goto tok_match_sub
+ oper = newfrom(mob, wspos, match)
+ $I0 = length key
+ $I0 += wspos
+ $P0 = getattribute oper, "PGE::Match\x0$:pos"
+ $P0 = $I0
+ goto tok_match_end
+ tok_match_sub:
+ oper = match(mob)
+ tok_match_end:
+ $P0 = tok["name"]
+ $P0 = clone $P0
+ oper["name"] = $P0
+ ret
+
+ end:
+ $I0 = elements tokstack
+ if $I0 < 1 goto end_1
+ bsr reduce
+ goto end
+ end_1:
+ $P0 = pop termstack
+ mob["expr"] = $P0
+ mobpos = pos
+ .return (mob)
+
+ term_error:
+ $P0 = new Exception
+ $S0 = "Missing term at offset "
+ $S1 = wspos
+ $S0 .= $S1
+ $S0 .= "\n"
+ $P0["_message"] = $S0
+ throw $P0
+ mobpos = -1
+ .return (mob)
+.end
+
+
Modified: trunk/config/gen/makefiles/pge.in
==============================================================================
--- trunk/config/gen/makefiles/pge.in (original)
+++ trunk/config/gen/makefiles/pge.in Tue Oct 25 23:55:38 2005
@@ -16,7 +16,7 @@ all: $(PARROT_LIBRARY)${slash}PGE.pbc
$(PARROT_LIBRARY)${slash}PGE.pbc: PGE.pbc
$(CP) PGE.pbc $(PARROT_LIBRARY)
-PGE.pbc: PGE.pir PGE/Exp.pir PGE/Match.pir PGE/Rule.pir PGE/P6Rule.pir
PGE/TokenHash.pir mklib.pir library.pge
+PGE.pbc: PGE.pir PGE/Exp.pir PGE/Match.pir PGE/Rule.pir PGE/P6Rule.pir
PGE/TokenHash.pir PGE/OPTable.pir mklib.pir library.pge
$(PARROT) mklib.pir >PGE/Library.pir
$(PARROT) -o PGE.pbc --output-pbc PGE.pir
Modified: trunk/lib/Parrot/Test/PGE.pm
==============================================================================
--- trunk/lib/Parrot/Test/PGE.pm (original)
+++ trunk/lib/Parrot/Test/PGE.pm Tue Oct 25 23:55:38 2005
@@ -147,6 +147,7 @@ sub _generate_pir_for {
.sub _PGE_Test
.local pmc p6rule_compile
load_bytecode "PGE.pbc"
+ load_bytecode "PGE/Dumper.pir"
load_bytecode "PGE/Text.pir"
find_global p6rule_compile, "PGE", "p6rule"
Modified: trunk/runtime/parrot/library/PGE/Dumper.pir
==============================================================================
--- trunk/runtime/parrot/library/PGE/Dumper.pir (original)
+++ trunk/runtime/parrot/library/PGE/Dumper.pir Tue Oct 25 23:55:38 2005
@@ -7,6 +7,199 @@ PGE::Dumper - various methods for displa
.sub __onload
.end
+.namespace [ "PGE::Match" ]
+
+=head2 C<PGE::Match> Methods
+
+=item C<__dump(PMC dumper, STR label)>
+
+This method enables Data::Dumper to work on Match objects.
+
+=cut
+
+.sub "__dump" :method
+ .param pmc dumper
+ .param string label
+ .local string indent, subindent
+
+ (indent, subindent) = dumper."newIndent"()
+ print "=> "
+ $S0 = self
+ dumper."genericString"("", $S0)
+ print " @ "
+ $I0 = self.from()
+ print $I0
+ $P0 = self."get_array"()
+ if_null $P0, dump_1
+ print "\n"
+ print indent
+ dumper."dump"(label, $P0)
+ dump_1:
+ $P0 = self."get_hash"()
+ if_null $P0, dump_end
+ print "\n"
+ print indent
+ dumper."dump"(label, $P0)
+ goto dump_end
+ dump_end:
+ dumper."deleteIndent"()
+.end
+
+=item C<dump()>
+
+An alternate dump output for a Match object and all of its subcaptures.
+
+=cut
+
+.sub "dump" method
+ .param string prefix :optional # name of match variable
+ .param int has_prefix :opt_flag
+ .param string b1 :optional # bracket open
+ .param int has_b1 :opt_flag
+ .param string b2 :optional # bracket close
+ .param int has_b2 :opt_flag
+
+ .local pmc capt
+ .local int spi, spc
+ .local pmc iter
+ .local string prefix1, prefix2
+
+ if has_b2 goto start
+ b2 = "]"
+ if has_b1 goto start
+ b1 = "["
+ start:
+ print prefix
+ print ":"
+ unless self goto subpats
+ print " <"
+ print self
+ print " @ "
+ $I0 = self."from"()
+ print $I0
+ print "> "
+
+ subpats:
+ $I0 = self
+ print $I0
+ print "\n"
+ capt = getattribute self, "PGE::Match\x0@:capt"
+ if_null capt, subrules
+ spi = 0
+ spc = elements capt
+ subpats_1:
+ unless spi < spc goto subrules
+ prefix1 = concat prefix, b1
+ $S0 = spi
+ concat prefix1, $S0
+ concat prefix1, b2
+ $I0 = defined capt[spi]
+ unless $I0 goto subpats_2
+ $P0 = capt[spi]
+ bsr dumper
+ subpats_2:
+ inc spi
+ goto subpats_1
+
+ subrules:
+ capt = getattribute self, "PGE::Match\x0%:capt"
+ if_null capt, end
+ iter = new Iterator, capt
+ iter = 0
+ subrules_1:
+ unless iter goto end
+ $S0 = shift iter
+ prefix1 = concat prefix, "<"
+ concat prefix1, $S0
+ concat prefix1, ">"
+ $I0 = defined capt[$S0]
+ unless $I0 goto subrules_1
+ $P0 = capt[$S0]
+ bsr dumper
+ goto subrules_1
+
+ dumper:
+ $I0 = isa $P0, "Array"
+ if $I0 goto dumper_0
+ $I0 = isa $P0, "PGE::Match"
+ unless $I0 goto dumper_3
+ $P0."dump"(prefix1, b1, b2)
+ ret
+ dumper_0:
+ $I0 = 0
+ $I1 = elements $P0
+ dumper_1:
+ if $I0 >= $I1 goto dumper_2
+ $P1 = $P0[$I0]
+ prefix2 = concat prefix1, b1
+ $S0 = $I0
+ concat prefix2, $S0
+ concat prefix2, b2
+ $P1."dump"(prefix2, b1, b2)
+ inc $I0
+ goto dumper_1
+ dumper_2:
+ ret
+ dumper_3:
+ print prefix1
+ print ": "
+ print $P0
+ print "\n"
+ ret
+
+ end:
+ .return ()
+.end
+
+.namespace [ "PGE::Op" ]
+
+=head2 C<PGE::Op> methods
+
+=item C<__dump(PMC dumper, STR label)>
+
+For C<PGE::Op> objects (often produced by the shift/reduce
+parser in C<PGE::OPTable>), it's perhaps useful to have an
+alternate Data::Dumper format that makes the operator
+precedence more obvious.
+
+=cut
+
+.sub "__dump" :method
+ .param pmc dumper
+ .param string label
+ .local string indent, subindent
+
+ (indent, subindent) = dumper."newIndent"()
+ $P0 = self["name"]
+ print "=> "
+ print $P0
+ print " => "
+ $S0 = self
+ dumper."genericString"("", $S0)
+ $I0 = defined self["args"]
+ if $I0 == 0 goto end
+ $P0 = self["args"]
+ $I1 = elements $P0
+ $I0 = 0
+ dump_args:
+ if $I0 >= $I1 goto end
+ print "\n"
+ print indent
+ $P1 = $P0[$I0]
+ dumper."dump"(label, $P1)
+ inc $I0
+ goto dump_args
+ end:
+ dumper."deleteIndent"()
+.end
+
+=head2 C<PGE::Exp> methods
+
+These methods print out a PGE expression tree. They may be
+obsoleted in favor of a Data::Dumper method.
+
+=cut
+
.namespace [ "PGE::Exp" ]
.sub "dumpindent" method