gen_peg_me.tcl

Go to the documentation of this file.
00001 /*  -*- tcl -*-*/
00002 /* */
00003 /*  Copyright (c) 2005 by Andreas Kupries <andreas_kupries@users.sourceforge.net>*/
00004 /*  Parser Generator / Backend - Generate a grammar::mengine based parser.*/
00005 
00006 /*  This package assumes to be used from within a PAGE plugin. It uses*/
00007 /*  the API commands listed below. These are identical across the major*/
00008 /*  types of PAGE plugins, allowing this package to be used in reader,*/
00009 /*  transform, and writer plugins. It cannot be used in a configuration*/
00010 /*  plugin, and this makes no sense either.*/
00011 /* */
00012 /*  To ensure that our assumption is ok we require the relevant pseudo*/
00013 /*  package setup by the PAGE plugin management code.*/
00014 /* */
00015 /*  -----------------+--*/
00016 /*  page_info        | Reporting to the user.*/
00017 /*  page_warning     |*/
00018 /*  page_error       |*/
00019 /*  -----------------+--*/
00020 /*  page_log_error   | Reporting of internals.*/
00021 /*  page_log_warning |*/
00022 /*  page_log_info    |*/
00023 /*  -----------------+--*/
00024 
00025 /*  ### ### ### ######### ######### #########*/
00026 /*  Dumping the input grammar. But not as Tcl or other code. In PEG*/
00027 /*  format again, pretty printing.*/
00028 
00029 /*  ### ### ### ######### ######### #########*/
00030 /*  Requisites*/
00031 
00032 /*  @mdgen NODEP: page::plugin*/
00033 
00034 package require page::plugin ; /*  S.a. pseudo-package.*/
00035 
00036 package require textutil
00037 package require page::analysis::peg::emodes
00038 package require page::util::quote
00039 package require page::util::peg
00040 
00041 namespace ::page::gen::peg::me {
00042     /*  Get the peg char de/encoder commands.*/
00043     /*  (unquote, quote'tcl)*/
00044 
00045     namespace import ::page::util::quote::*
00046     namespace import ::page::util::peg::*
00047 }
00048 
00049 /*  ### ### ### ######### ######### #########*/
00050 /*  API*/
00051 
00052 ret  ::page::gen::peg::me::package (type text) {
00053     variable package $text
00054     return
00055 }
00056 
00057 ret  ::page::gen::peg::me::copyright (type text) {
00058     variable copyright $text
00059     return
00060 }
00061 
00062 ret  ::page::gen::peg::me (type t , type chan) {
00063     variable me::package
00064     variable me::copyright
00065 
00066     # Resolve the mode hints. Every gen(X) having a value of 'maybe'
00067     # (or missing) is for the purposes of this code a 'yes'.
00068 
00069     if {![page::analysis::peg::emodes::compute $t]} {
00070     page_error "  Unable to generate a ME parser without accept/generate properties"
00071     return
00072     }
00073 
00074     foreach n [$t nodes] {
00075     if {![$t keyexists $n gen] || ([$t get $n gen] eq "maybe")} {
00076         $t set $n gen 1
00077     }
00078     if {![$t keyexists $n acc]} {$t set $n acc 1}
00079     }
00080 
00081     $t set root Pcount 0
00082 
00083     $t set root package   $package
00084     $t set root copyright $copyright
00085 
00086     # Synthesize all text fragments we need.
00087     me::Synth $t
00088 
00089     # And write the grammar text.
00090     puts $chan [$t get root TEXT]
00091     return
00092 }
00093 
00094 /*  ### ### ### ######### ######### #########*/
00095 /*  Internal. Helpers*/
00096 
00097 ret  ::page::gen::peg::me::Synth (type t) {
00098     # Phase 2: Bottom-up, synthesized attributes
00099     #
00100     # - Text blocks per node.
00101 
00102     $t walk root -order post -type dfs n {
00103     SynthNode $t $n
00104     }
00105     return
00106 }
00107 
00108 ret  ::page::gen::peg::me::SynthNode (type t , type n) {
00109     if {$n eq "root"} {
00110     set code Root
00111     } elseif {[$t keyexists $n symbol]} {
00112     set code Nonterminal
00113     } elseif {[$t keyexists $n op]} {
00114     set code [$t get $n op]
00115     } else {
00116     return -code error "PANIC. Bad node $n, cannot classify"
00117     }
00118 
00119     #puts stderr "SynthNode/$code $t $n"
00120 
00121     SynthNode/$code $t $n
00122 
00123     #SHOW [$t get $n TEXT] 1 0
00124     #catch {puts stderr "\t.[$t get $n W]x[$t get $n H]"}
00125     return
00126 }
00127 
00128 ret  ::page::gen::peg::me::SynthNode/Root (type t , type n) {
00129     variable template
00130 
00131     # Root is the grammar itself.
00132 
00133     # Text blocks we have to combine:
00134     # - Code for matching the start expression
00135     # - Supporting code for the above.
00136     # - Code per Nonterminal definition.
00137 
00138     set gname    [$t get root name]
00139     set gstart   [$t get root start]
00140     set gpackage [$t get root package]
00141     set gcopy    [$t get root copyright]
00142 
00143     if {$gcopy ne ""} {
00144     set gcopyright "## (C) $gcopy\n"
00145     } else {
00146     set gcopyright ""
00147     }
00148     if {$gpackage eq ""} {
00149     set gpackage $gname
00150     }
00151 
00152     page_info "  Grammar:   $gname"
00153     page_info "  Package:   $gpackage"
00154     if {$gcopy ne ""} {
00155     page_info "  Copyright: $gcopy"
00156     }
00157 
00158     if {$gstart ne ""} {
00159     set match   [textutil::indent \
00160         [$t get $gstart MATCH] \
00161         "    "]
00162     } else {
00163     page_error "  No start expression."
00164     set match ""
00165     }
00166 
00167     set crules {}
00168     set rules  {}
00169     set support [$t get [$t get root start] SUPPORT]
00170     if {[string length $support]} {
00171     lappend rules $support
00172     lappend rules {}
00173     }
00174 
00175     lappend crules "# Grammar '$gname'"
00176     lappend crules {#}
00177 
00178     array set def [$t get root definitions]
00179     foreach sym [lsort -dict [array names def]]  {
00180     lappend crules [Pfx "# " [$t get $def($sym) EXPR]]
00181     lappend crules {#}
00182 
00183     lappend rules  [$t get $def($sym) TEXT]
00184     lappend rules {}
00185     }
00186     set rules [join [lrange $rules 0 end-1] \n]
00187 
00188     lappend crules {}
00189     lappend crules $rules
00190 
00191     set crules [join $crules \n]
00192 
00193     # @PKG@ and @NAME@ are handled after the other expansions as their
00194     # contents may insert additional instances of these placeholders.
00195 
00196     $t set root TEXT \
00197     [string map \
00198         [list \
00199             @NAME@ $gname \
00200             @PKG@  $gpackage \
00201             @COPY@ $gcopyright] \
00202         [string map \
00203             [list \
00204             @MATCH@ $match \
00205             @RULES@ $crules \
00206             ] $template]]
00207     return
00208 }
00209 
00210 ret  ::page::gen::peg::me::SynthNode/Nonterminal (type t , type n) {
00211     # This is the root of a definition.
00212     #
00213     # The text is a procedure wrapping the match code of its
00214     # expression into the required the nonterminal handling (caching
00215     # and such), plus the support code for the expression matcher.
00216 
00217     set sym      [$t get $n symbol]
00218     set label    [$t get $n label]
00219     set gen      [$t get $n gen]
00220     set mode     [$t get $n mode]
00221 
00222     set pe       [lindex [$t children $n] 0]
00223     set egen     [$t get $pe gen]
00224     set esupport [$t get $pe SUPPORT]
00225     set ematch   [$t get $pe MATCH]
00226     set eexpr    [$t get $pe EXPR]
00227 
00228     # Combine the information.
00229 
00230     set sexpr    [Cat "$sym = " $eexpr]
00231 
00232     set match {}
00233     #lappend match "puts stderr \"$label << \[icl_get\]\""
00234     #lappend match {}
00235     lappend match [Pfx "# " $sexpr]
00236     lappend match {}
00237     if {$gen} {
00238     lappend match {variable ok}
00239     lappend match "if \{\[inc_restore $label\]\} \{"
00240     lappend match "    if \{\$ok\} ias_push"
00241     #lappend match "    puts stderr \">> $label = \$ok (c) \[icl_get\]\""
00242     lappend match "    return"
00243     lappend match "\}"
00244     } else {
00245     set eop [$t get $pe op]
00246     if {
00247         ($eop eq "t")     || ($eop eq "..") ||
00248         ($eop eq "alpha") || ($eop eq "alnum")
00249     } {
00250         # Required iff !dot
00251         # Support for terminal expression 
00252         lappend match {variable ok}
00253     }
00254 
00255     #lappend match "variable ok"
00256     lappend match "if \{\[inc_restore $label\]\} return"
00257     #lappend match "if \{\[inc_restore $label\]\} \{"
00258     #lappend match "    puts stderr \">> $label = \$ok (c) \[icl_get\]\""
00259     #lappend match "    return"
00260     #lappend match "\}"
00261     }
00262     lappend match {}
00263     lappend match {set pos [icl_get]}
00264     if {$egen} {
00265     # [*] Needed for removal of SV's from stack after handling by
00266     # this symbol, only if expression actually generates an SV.
00267     lappend match {set mrk [ias_mark]}
00268     }
00269     lappend match {}
00270     lappend match $ematch
00271     lappend match {}
00272 
00273     switch -exact -- $mode {
00274     value   {lappend match "isv_nonterminal_reduce $label \$pos \$mrk"}
00275     match   {lappend match "isv_nonterminal_range  $label \$pos"}
00276     leaf    {lappend match "isv_nonterminal_leaf   $label \$pos"}
00277     discard {lappend match "isv_clear"}
00278     default {return -code error "Bad nonterminal mode \"$mode\""}
00279     }
00280 
00281     lappend match "inc_save               $label \$pos"
00282     if {$egen} {
00283     # See [*], this is the removal spoken about before.
00284     lappend match {ias_pop2mark             $mrk}
00285     }
00286     if {$gen} {
00287     lappend match {if {$ok} ias_push}
00288     }
00289     lappend match "ier_nonterminal        \"Expected $label\" \$pos"
00290     #lappend match "puts stderr \">> $label = \$ok \[icl_get\]\""
00291     lappend match return
00292 
00293     # Final assembly
00294 
00295     set pname [Call $sym]
00296     set match [list [Proc $pname [join $match \n]]]
00297 
00298     if {[string length $esupport]} {
00299     lappend match {}
00300     lappend match $esupport
00301     }
00302 
00303     $t set $n TEXT [join $match \n]
00304     $t set $n EXPR $sexpr
00305     return
00306 }
00307 
00308 ret  ::page::gen::peg::me::SynthNode/? (type t , type n) {
00309     # The expression e? is equivalent to e/epsilon.
00310     # And like this it is compiled.
00311 
00312     set pe       [lindex [$t children $n] 0]
00313     set ematch   [$t get $pe MATCH]
00314     set esupport [$t get $pe SUPPORT]
00315     set eexpr    [$t get $pe EXPR]
00316     set egen     [$t get $pe gen]
00317     set sexpr    "[Cat "(? " $eexpr])"
00318 
00319     set     match {}
00320     lappend match {}
00321     lappend match [Pfx "# " $sexpr]
00322     lappend match {}
00323     lappend match {variable ok}
00324     lappend match {}
00325     lappend match {set pos [icl_get]}
00326     lappend match {}
00327     lappend match {set old [ier_get]}
00328     lappend match $ematch
00329     lappend match {ier_merge $old}
00330     lappend match {}
00331     lappend match {if {$ok} return}
00332     lappend match {icl_rewind $pos}
00333     lappend match {iok_ok}
00334     lappend match {return}
00335 
00336     # Final assembly
00337 
00338     set pname [NextProc $t opt]
00339     set match [list [Proc $pname [join $match \n]]]
00340     if {[string length $esupport]} {
00341     lappend match {}
00342     lappend match $esupport
00343     }
00344 
00345     $t set $n EXPR    $sexpr
00346     $t set $n MATCH   [Cat "$pname                ; " [Pfx "# " $sexpr]]
00347     $t set $n SUPPORT [join $match \n]
00348     return
00349 }
00350 
00351 ret  ::page::gen::peg::me::SynthNode/* (type t , type n) {
00352     # Kleene star is like a repeated ?
00353 
00354     # Note: Compilation as while loop, as done now
00355     # means that the parser has no information about
00356     # the intermediate structure of the input in his
00357     # cache.
00358 
00359     # Future: Create a helper symbol X and compile
00360     # the expression e = e'* as:
00361     #     e = X; X <- (e' X)?
00362     # with match data for X put into the cache. This
00363     # is not exactly equivalent, the structure of the
00364     # AST is different (right-nested tree instead of
00365     # a list). This however can be handled with a
00366     # special nonterminal mode to expand the current
00367     # SV on the stack.
00368 
00369     # Note 2: This is a transformation which can be
00370     # done on the grammar itself, before the actual
00371     # backend is let loose. This "strength reduction"
00372     # allows us to keep this code here.
00373 
00374     set pe       [lindex [$t children $n] 0]
00375     set ematch   [$t get $pe MATCH]
00376     set esupport [$t get $pe SUPPORT]
00377     set eexpr    [$t get $pe EXPR]
00378     set egen     [$t get $pe gen]
00379     set sexpr    "[Cat "(* " $eexpr])"
00380 
00381     set     match {}
00382     lappend match {}
00383     lappend match [Pfx "# " $sexpr]
00384     lappend match {}
00385     lappend match {variable ok}
00386     lappend match {}
00387     lappend match "while \{1\} \{"
00388     lappend match {    set pos [icl_get]}
00389     lappend match {}
00390     lappend match {    set old [ier_get]}
00391     lappend match [textutil::indent $ematch "    "]
00392     lappend match {    ier_merge $old}
00393     lappend match {}
00394     lappend match {    if {$ok} continue}
00395     lappend match {    break}
00396     lappend match "\}"
00397     lappend match {}
00398     lappend match {icl_rewind $pos}
00399     lappend match {iok_ok}
00400     lappend match {return}
00401 
00402     # Final assembly
00403 
00404     set pname [NextProc $t kleene]
00405     set match [list [Proc $pname [join $match \n]]]
00406     if {[string length $esupport]} {
00407     lappend match {}
00408     lappend match $esupport
00409     }
00410 
00411     $t set $n MATCH   [Cat "$pname                ; " [Pfx "# " $sexpr]]
00412     $t set $n SUPPORT [join $match \n]
00413     $t set $n EXPR    $sexpr
00414     return
00415 }
00416 
00417 ret  ::page::gen::peg::me::SynthNode/+ (type t , type n) {
00418     # Positive Kleene star x+ is equivalent to x x*
00419     # This is how it is compiled. See also the notes
00420     # at the * above, they apply in essence here as
00421     # well, except that the transformat scheme is
00422     # slighty different:
00423     #
00424     # e = e'*  ==> e = X; X <- e' X?
00425 
00426     set pe       [lindex [$t children $n] 0]
00427     set ematch   [$t get $pe MATCH]
00428     set esupport [$t get $pe SUPPORT]
00429     set eexpr    [$t get $pe EXPR]
00430     set egen     [$t get $pe gen]
00431     set sexpr    "[Cat "(+ " $eexpr])"
00432 
00433     set     match {}
00434     lappend match {}
00435     lappend match [Pfx "# " $sexpr]
00436     lappend match {}
00437     lappend match {variable ok}
00438     lappend match {}
00439     lappend match {set pos [icl_get]}
00440     lappend match {}
00441     lappend match {set old [ier_get]}
00442     lappend match $ematch
00443     lappend match {ier_merge $old}
00444     lappend match {}
00445     lappend match "if \{!\$ok\} \{"
00446     lappend match {    icl_rewind $pos}
00447     lappend match {    return}
00448     lappend match "\}"
00449     lappend match {}
00450     lappend match "while \{1\} \{"
00451     lappend match {    set pos [icl_get]}
00452     lappend match {}
00453     lappend match {    set old [ier_get]}
00454     lappend match [textutil::indent $ematch "    "]
00455     lappend match {    ier_merge $old}
00456     lappend match {}
00457     lappend match {    if {$ok} continue}
00458     lappend match {    break}
00459     lappend match "\}"
00460     lappend match {}
00461     lappend match {icl_rewind $pos}
00462     lappend match {iok_ok}
00463     lappend match {return}
00464 
00465     # Final assembly
00466 
00467     set pname [NextProc $t pkleene]
00468     set match [list [Proc $pname [join $match \n]]]
00469     if {[string length $esupport]} {
00470     lappend match {}
00471     lappend match $esupport
00472     }
00473 
00474     $t set $n MATCH   [Cat "$pname                ; " [Pfx "# " $sexpr]]
00475     $t set $n SUPPORT [join $match \n]
00476     $t set $n EXPR    $sexpr
00477     return
00478 }
00479 
00480 ret  ::page::gen::peg::me::SynthNode// (type t , type n) {
00481     set args [$t children $n]
00482 
00483     if {![llength $args]} {
00484     error "PANIC. Empty choice."
00485 
00486     } elseif {[llength $args] == 1} {
00487     # A choice over one branch is no real choice. The code
00488     # generated for the child applies here as well.
00489 
00490     set pe [lindex $args 0]
00491     $t set $n MATCH   [$t get $pe MATCH]
00492     $t set $n SUPPORT [$t get $pe SUPPORT]
00493     return
00494     }
00495 
00496     # Choice over at least two branches.
00497 
00498     set match   {}
00499     set support {}
00500     set sexpr   {}
00501 
00502     lappend match {}
00503     lappend match {}
00504     lappend match {variable ok}
00505     lappend match {}
00506     lappend match {set pos [icl_get]}
00507     foreach pe $args {
00508     lappend match {}
00509 
00510     set ematch   [$t get $pe MATCH]
00511     set esupport [$t get $pe SUPPORT]
00512     set eexpr    [$t get $pe EXPR]
00513     set egen     [$t get $pe gen]
00514 
00515     # Note: We do not check for static match results. Doing so is
00516     # an optimization we can do earlier, directly on the tree.
00517 
00518     lappend sexpr $eexpr
00519 
00520     if {[string length $esupport]} {
00521         lappend support {}
00522         lappend support $esupport
00523     }
00524 
00525     if {$egen} {
00526         lappend match "set mrk \[ias_mark\]"
00527     }
00528 
00529     lappend match "set old \[ier_get\]"
00530     lappend match $ematch
00531     lappend match "ier_merge \$old"
00532     lappend match {}
00533     lappend match "if \{\$ok\} return"
00534 
00535     if {$egen} {
00536         lappend match "ias_pop2mark \$mrk"
00537     }
00538     lappend match "icl_rewind   \$pos"
00539     }
00540     lappend match {}
00541     lappend match return
00542 
00543     # Final assembly
00544 
00545     set sexpr "[Cat "(/ " [join $sexpr \n]])"
00546     set match [linsert $match 1 [Pfx "# " $sexpr]]
00547 
00548     set pname [NextProc $t bra]
00549     set match [list [Proc $pname [join $match \n]]]
00550     if {[llength $support]} {
00551     lappend match {}
00552     lappend match [join [lrange $support 1 end] \n]
00553     }
00554 
00555     $t set $n MATCH   [Cat "$pname                ; " [Pfx "# " $sexpr]]
00556     $t set $n SUPPORT [join $match \n]
00557     $t set $n EXPR    $sexpr
00558     return
00559 }
00560 
00561 ret  ::page::gen::peg::me::SynthNode/x (type t , type n) {
00562     set args [$t children $n]
00563 
00564     if {![llength $args]} {
00565     error "PANIC. Empty sequence."
00566 
00567     } elseif {[llength $args] == 1} {
00568     # A sequence of one element is no real sequence. The code
00569     # generated for the child applies here as well.
00570 
00571     set pe [lindex $args 0]
00572     $t set $n MATCH   [$t get $pe MATCH]
00573     $t set $n SUPPORT [$t get $pe SUPPORT]
00574     $t set $n EXPR    [$t get $pe EXPRE]
00575     return
00576     }
00577 
00578     # Sequence of at least two elements.
00579 
00580     set match   {}
00581     set support {}
00582     set sexpr   {}
00583     set gen     0
00584 
00585     lappend match {}
00586     lappend match {}
00587     lappend match {variable ok}
00588     lappend match {}
00589     lappend match {set pos [icl_get]}
00590 
00591     foreach pe $args {
00592     lappend match {}
00593 
00594     set ematch   [$t get $pe MATCH]
00595     set esupport [$t get $pe SUPPORT]
00596     set eexpr    [$t get $pe EXPR]
00597     set egen     [$t get $pe gen]
00598 
00599     lappend sexpr $eexpr
00600 
00601     if {[string length $esupport]} {
00602         lappend support {}
00603         lappend support $esupport
00604     }
00605 
00606     if {$egen && !$gen} {
00607         # From here on out is the sequence
00608         # able to generate semantic values
00609         # which have to be canceled when
00610         # backtracking.
00611 
00612         lappend match "set mrk \[ias_mark\]"
00613         lappend match {}
00614         set gen 1
00615     }
00616 
00617     lappend match "set old \[ier_get\]"
00618     lappend match $ematch
00619     lappend match "ier_merge \$old"
00620     lappend match {}
00621 
00622     if {$gen} {
00623         lappend match "if \{!\$ok\} \{"
00624         lappend match "    ias_pop2mark \$mrk"
00625         lappend match "    icl_rewind   \$pos"
00626         lappend match "    return"
00627         lappend match "\}"
00628     } else {
00629         lappend match "if \{!\$ok\} \{icl_rewind \$pos \; return\}"
00630     }
00631     }
00632     lappend match {}
00633     lappend match return
00634 
00635     # Final assembly
00636 
00637     set sexpr "[Cat "(x " [join $sexpr \n]])"
00638     set match [linsert $match 1 [Pfx "# " $sexpr]]
00639 
00640     set pname [NextProc $t seq]
00641     set match [list [Proc $pname [join $match \n]]]
00642     if {[llength $support]} {
00643     lappend match {}
00644     lappend match [join [lrange $support 1 end] \n]
00645     }
00646 
00647     $t set $n MATCH   [Cat "$pname                ; " [Pfx "# " $sexpr]]
00648     $t set $n SUPPORT [join $match \n]
00649     $t set $n EXPR    $sexpr
00650     return
00651 }
00652 
00653 ret  ::page::gen::peg::me::SynthNode/& (type t , type n) {
00654     SynthLookahead $t $n no
00655     return
00656 }
00657 
00658 ret  ::page::gen::peg::me::SynthNode/! (type t , type n) {
00659     SynthLookahead $t $n yes
00660     return
00661 }
00662 
00663 ret  ::page::gen::peg::me::SynthNode/dot (type t , type n) {
00664     SynthTerminal $t $n \
00665         "any character" {}
00666     $t set $n EXPR "(dot)"
00667     return
00668 }
00669 
00670 ret  ::page::gen::peg::me::SynthNode/epsilon (type t , type n) {
00671     $t set $n MATCH   iok_ok
00672     $t set $n SUPPORT {}
00673     $t set $n EXPR "(epsilon)"
00674     return
00675 }
00676 
00677 ret  ::page::gen::peg::me::SynthNode/alnum (type t , type n) {
00678     SynthClass $t $n alnum
00679     return
00680 }
00681 
00682 ret  ::page::gen::peg::me::SynthNode/alpha (type t , type n) {
00683     SynthClass $t $n alpha
00684     return
00685 }
00686 
00687 ret  ::page::gen::peg::me::SynthNode/.. (type t , type n) {
00688     # Range is [x-y]
00689 
00690     set b [$t get $n begin]
00691     set e [$t get $n end]
00692 
00693     set tb [quote'tcl $b]
00694     set te [quote'tcl $e]
00695 
00696     set pb [quote'tclstr $b]
00697     set pe [quote'tclstr $e]
00698 
00699     set cb [quote'tclcom $b]
00700     set ce [quote'tclcom $e]
00701 
00702     SynthTerminal $t $n \
00703         "\\\[${pb}..${pe}\\\]" \
00704         "ict_match_tokrange $tb $te"
00705     $t set $n EXPR "(.. $cb $ce)"
00706     return
00707 }
00708 
00709 ret  ::page::gen::peg::me::SynthNode/t (type t , type n) {
00710     # Terminal node. Primitive matching.
00711     # Code is parameterized by gen(X) of this node X.
00712 
00713     set ch  [$t get $n char]
00714     set tch [quote'tcl    $ch]
00715     set pch [quote'tclstr $ch]
00716     set cch [quote'tclcom $ch]
00717 
00718     SynthTerminal $t $n \
00719         $pch \
00720         "ict_match_token $tch"
00721     $t set $n EXPR    "(t $cch)"
00722     return
00723 }
00724 
00725 ret  ::page::gen::peg::me::SynthNode/n (type t , type n) {
00726     # Nonterminal node. Primitive matching.
00727     # The code is parameterized by acc(X) of this node X, and gen(D)
00728     # of the invoked nonterminal D.
00729 
00730     set sym   [$t get $n sym]
00731     set def   [$t get $n def]
00732 
00733     if {$def eq ""} {
00734     # Invokation of an undefined nonterminal. This will always fail.
00735     set match "iok_fail ; # Match for undefined symbol '$sym'."
00736     } else {
00737     # Combinations
00738     # Acc Gen Action
00739     # --- --- ------
00740     #   0   0 Plain match
00741     #   0   1 Match with canceling of the semantic value.
00742     #   1   0 Plain match
00743     #   1   1 Plain match
00744     # --- --- ------
00745 
00746     if {[$t get $n acc] || ![$t get $def gen]} {
00747         set match [Call $sym]
00748     } else {
00749         set     match {}
00750         lappend match "set p$sym \[ias_mark\]"
00751         lappend match [Call $sym]
00752         lappend match "ias_pop2mark \$p$sym"
00753         set match [join $match \n]
00754     }
00755     }
00756 
00757     set sexpr "(n $sym)"
00758     $t set $n EXPR    $sexpr
00759     $t set $n MATCH   "$match    ; # $sexpr"
00760     $t set $n SUPPORT {}
00761     return
00762 }
00763 
00764 ret  ::page::gen::peg::me::SynthLookahead (type t , type n , type negated) {
00765     # Note: Per the rules about expression modes (! is a lookahead
00766     # ____| operator) this node has a mode of 'discard', and its child
00767     # ____| has so as well.
00768 
00769     # assert t get n  mode == discard
00770     # assert t get pe mode == discard
00771 
00772     set op       [$t get $n op]
00773     set pe       [lindex [$t children $n] 0]
00774     set eop      [$t get $pe op]
00775     set ematch   [$t get $pe MATCH]
00776     set esupport [$t get $pe SUPPORT]
00777     set eexpr    [$t get $pe EXPR]
00778     set pname    [NextProc $t bang]
00779 
00780     set     match {}
00781 
00782     if {
00783     ($eop eq "t")     || ($eop eq "..") ||
00784     ($eop eq "alpha") || ($eop eq "alnum")
00785     } {
00786     # Required iff !dot
00787     # Support for terminal expression 
00788     lappend match {variable ok}
00789     lappend match {}
00790     }
00791 
00792     lappend match {set pos [icl_get]}
00793     lappend match {}
00794     lappend match $ematch
00795     lappend match {}
00796     lappend match {icl_rewind $pos}
00797 
00798     if {$negated} {
00799     lappend match {iok_negate}
00800     }
00801 
00802     lappend match return
00803 
00804     set match [list [Proc $pname [join $match \n]]]
00805     if {[string length $esupport]} {
00806     lappend match {}
00807     lappend match $esupport
00808     }
00809 
00810     $t set $n MATCH   $pname
00811     $t set $n SUPPORT [join $match \n]
00812     $t set $n EXPR    "($op $eexpr)"
00813     return
00814 }
00815 
00816 ret  ::page::gen::peg::me::SynthClass (type t , type n , type op) {
00817     SynthTerminal $t $n \
00818         <$op> \
00819         "ict_match_tokclass $op"
00820     $t set $n EXPR ($op)
00821     return
00822 }
00823 
00824 ret  ::page::gen::peg::me::SynthTerminal (type t , type n , type msg , type cmd) {
00825     set     match {}
00826     lappend match "ict_advance \"Expected $msg (got EOF)\""
00827 
00828     if {$cmd ne ""} {
00829     lappend match "if \{\$ok\} \{$cmd \"Expected $msg\"\}"
00830     }
00831     if {[$t get $n gen]} {
00832     lappend match "if \{\$ok\} isv_terminal"
00833     }
00834 
00835     $t set $n MATCH   [join $match \n]
00836     $t set $n SUPPORT {}
00837     return
00838 }
00839 
00840 ret  ::page::gen::peg::me::Call (type sym) {
00841     # Generator for proc names (nonterminal symbols).
00842     return matchSymbol_$sym
00843 }
00844 
00845 ret  ::page::gen::peg::me::NextProc (type t , optional mark ={)} {
00846     set  count [$t get root Pcount]
00847     incr count
00848     $t set root Pcount $count
00849     return e$mark$count
00850 }
00851 
00852 proc ::page::gen::peg::me::Proc {name body} {
00853     set     script {}
00854     lappend script "ret  ::@PKG@::$name \(\) \{"
00855     lappend script [::textutil::indent $body "    "]
00856     lappend script "\}"
00857     return [join $script \n]
00858 }
00859 
00860 ret  ::page::gen::peg::me::Cat (type prefix , type suffix) {
00861     return "$prefix[textutil::indent $suffix [textutil::blank [string length $prefix]] 1]"
00862 }
00863 
00864 ret  ::page::gen::peg::me::Pfx (type prefix , type suffix) {
00865     return [textutil::indent $suffix $prefix]
00866 }
00867 
00868 /*  ### ### ### ######### ######### #########*/
00869 /*  Internal. Strings.*/
00870 
00871 namespace ::page::gen::peg::me {
00872 
00873     variable here          [file dirname [info script]]
00874     variable template_file [file join $here gen_peg_me.template]
00875 
00876     variable ch
00877     variable template \
00878     [string trimright [read [ ch =  [open $template_file r]]][close $ch]]
00879     un ch = 
00880 
00881     variable package   ""
00882     variable copyright ""
00883 }
00884 
00885 /*  ### ### ### ######### ######### #########*/
00886 /*  Ready*/
00887 
00888 package provide page::gen::peg::me 0.1
00889 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1