gen_peg_me.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 package require page::plugin ;
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
00043
00044
00045 namespace import ::page::util::quote::*
00046 namespace import ::page::util::peg::*
00047 }
00048
00049
00050
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
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
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
00887
00888 package provide page::gen::peg::me 0.1
00889