parser-actions

This is a little utility to help generating a lot of similar procs or methods that might be necessary when evaluating a Parser Tools peg grammar.

 #!/usr/bin/env tclkit8.6
 #
 # parser-actions.tcl
 #
 # Many parser generators allow code to be associated with the grammar rules and
 # executed as the rules are recognized.  This script is a helper program to allow
 # action templates to be associated with [Parser Tools] peg grammar rules.
 #
 # When the peg parser returns the AST, it is executed as a tcl script.  This
 # allows the names of the PEG rules to be directly used as parser actions.  Each
 # parser rule corresponds to a proc (or method) of the parser.  In the grammar there
 # are many rules which share the same code, specifically many non-terminal rules whose
 # value is the concatenated values of their child rules and leaf rules whose values
 # are the underlying string or token that the rule matched.
 #
 # This proc allows the grammar file to "declare" the type of a rule in a following
 # comment.  The rule type is then associated with a template for that type and the
 # method is declared with the rule/action name and the code from the template.
 #
 proc parser-actions { file actions } {
    set reply {}
    foreach line [split [read [open $file]] \n] {
        switch -regexp -matchvar match $line {
            { *([a-zA-Z0-9_]+)[ \t]*<-[^;]*; *# *action ([a-zA-Z0-9_]+)[ \t]*} {
                append reply [string map [list %action [lindex $match 1]]       \
                    [dict get $actions [lindex $match 2]]] \n
            }
            { *([a-zA-Z0-9_]+)[ \t]*<-}   { set action [lindex $match 1] }
            {; *# *action ([a-zA-Z0-9_]+)[ \t]*$} {
                append reply [string map [list %action $action]                 \
                    [dict get $actions [lindex $match 1]]] \n
            }
        }
    }

    set reply
 }

 set parser [lindex $argv 0]    ;# A [Parser Tools] peg file w/annotations in comments.
 set action [lindex $argv 1]    ;# A file containing a dict of template procs.

 puts [parser-actions $parser                           \
         [regsub -all -line -- {((^[ \t]*)|([ \t]+))#.*$} [read [open $action]] { }]]