Author: pmichaud
Date: Wed May 30 10:11:10 2007
New Revision: 18690

Added:
   trunk/languages/abc/src/abc-2a.txt
Modified:
   trunk/MANIFEST
   trunk/languages/abc/src/abc-2.pg

Log:
(abc/PAST):
* More thoughts about a non-PIR based parse->AST transformation.


Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST      (original)
+++ trunk/MANIFEST      Wed May 30 10:11:10 2007
@@ -1022,6 +1022,7 @@
 languages/abc/config/makefiles/root.in                      [abc]
 languages/abc/src/PASTGrammar.tg                            [abc]
 languages/abc/src/abc-2.pg                                  [abc]
+languages/abc/src/abc-2a.txt                                [abc]
 languages/abc/src/abc.pg                                    [abc]
 languages/abc/src/builtins.pir                              [abc]
 languages/abc/t/01-tests.t                                  [abc]

Modified: trunk/languages/abc/src/abc-2.pg
==============================================================================
--- trunk/languages/abc/src/abc-2.pg    (original)
+++ trunk/languages/abc/src/abc-2.pg    Wed May 30 10:11:10 2007
@@ -1,5 +1,7 @@
 grammar ABC::Grammar;
 
+## DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
+
 ## an example 'bc' grammar
 ## This version uses a Perl 6 subset to build the abstract
 ## syntax tree as the program is being parsed, instead of a separate
@@ -11,38 +13,21 @@
 token TOP { <program> { return $<program> }; }
 
 ## recognize terms
-token float {
-    \d+ '.' \d* | '.' \d+
-        { return PAST::Val.new( :node($/), :vtype('.Float'), :name($/); }
-}
+token float { [ \d+ '.' \d* | '.' \d+ ]  {*}  }
 
-token integer {
-    \d+ 
-        { return PAST::Val.new( :node($/), :vtype('.Integer'), :name($/); }
-}
+token integer { \d+  {*} }
 
 ##  FIXME: still need to handle lvalue variables
-token variable {
-    <[a..z]><[_a..z0..9]>*
-        { return PAST::Var.new( :node($/), :name($/), :viviself('.Integer'); }
-}
+token variable { <[a..z]><[_a..z0..9]>*  {*} }
 
 ##  FIXME: still need to handle lvalue array
 token term {
-    | <float> { return $<float>; }
-    | <integer> { return $<integer>; }
+    | <float>                     {*#<float>}
+    | <integer>                   {*#<integer>}
     | <variable> 
-        [ '[' <expression> ']'
-            { return PAST::Var( $<variable>, $<expression>,
-                                :node($/), 
-                                :name($<variable>.text ~ '_array'),
-                                :viviself('.Integer') ); }
-        | '(' <expression> ')'
-            { return PAST::Op( $<expression>
-                               :node($/),
-                               :name($<variable>.text),
-                               :pasttype('call') ); }
-        | <null> { return $<variable>; }
+        [ '[' <expression> ']'    {*#<array>}
+        | '(' <expression> ')'    {*#<call>}
+        | <null>                  {*#<variable>}
         ]
 }
                                 
@@ -57,120 +42,113 @@
 }
 
 rule compound_statement { 
-    '{' <statement_list> '}'     { return $<statement_list>; }
+    '{' <statement_list> '}'     {*}
 }
 
 rule if_statement { 
     'if' '(' <expression> ')' <statement> 
     [ 'else' <statement> ]? 
-        { $x = PAST::Op.new( $<expression>, $<statement>[0], 
-                             :node($/), :pasttype('if') );
-          if ($<statement>[1]) { $x.push($<statement>[1]); }
-          return $x;
-        }
+    {*}
 }
 
 rule while_statement {
     'while' '(' <expression> ')' <statement>
-        { return PAST::Op.new( $<expression>, $<statement>,
-                               :node($/), :pasttype('while') );
-        }
+    {*}
 }
 
 rule for_statement {
     'for' '(' <expression> ; <expression> ; <expression> ')' <statement>
-        { $iter = PAST::Stmts.new( $<statement>, $<expression>[2] );
-          $loop = PAST::Op.new( $<expression>[1], $iter, :pasttype('while') );
-          return PAST::Stmts.new( $<expression>[0], $loop );
-        }
+    {*}
 }
 
 rule statement {
-    | <if_statement>          { return $<if_statement> ; }
-    | <while_statement>       { return $<while_statement>; }
-    | <for_statement>         { return $<for_statement>; }
-    | <compound_statement>    { return $<compound_statement>; }
+    | <if_statement>          {*#<if>}
+    | <while_statement>       {*#<while>}
+    | <for_statement>         {*#<for>}
+    | <compound_statement>    {*#<compound>} 
     | \" <string> \"
     | break
     | continue
     | halt
     | return [ \( <expression> \) ]?
-    | <expression>            { return $<expression>; }
+    | <expression>            {*#<expression> }
 }
 
 rule statement_list { 
     <statement>? [ ; <statement>? ]* 
-        { $stmts = PAST::Stmts.new( :node($/) );
-          for @$<statement> { $stmts.push( $_ ); }
-          return $stmts;
-        }
+    {*}
 }
 
 rule program { 
     ^ <statement_list> [ $ | <die: parse error> ] 
-        { return PAST::Block.new( :node($/), $<statement_list> ); }
+    {*}
 }
 
 rule pseudo_statement { limits | quit | warranty }
 
 ## FIXME :  still don't handle $<expression> as PAST
 ## create operator precedence parser
-rule 'expression'   is optable { ... }
-
 
-## terms
-proto 'term:'       is precedence('=')
-    is parsed(&term)
-    { ... }
+rule expression {
+    <EXPR> 
+    {*}
+}
 
-proto 'circumfix:( )'  is equiv('term:') 
+token circumfix:sym<( )> is equiv(&term)  
     is pirop('set')
     { ... }
 
 ## autoincrement
-proto 'postfix:++'  is looser('term:')     is lvalue(1) { ... }
-proto 'postfix:--'  is equiv('postfix:++') is lvalue(1) { ... }
-proto 'prefix:++'   is equiv('postfix:++') is lvalue(1) { ... }
-proto 'prefix:--'   is equiv('postfix:++') is lvalue(1) { ... }
+token postfix:sym<++> is looser(&circumfix:<( )>) 
+    is lvalue(1) 
+    { ... }
+token postfix:sym<--> is equiv(&postfix:<++>) is lvalue(1) { ... }
+token prefix:sym<++>  is equiv(&postfix:<++>) is lvalue(1) { ... }
+token prefix:sym<-->  is equiv(&postfix:<++>) is lvalue(1) { ... }
 
 ## negation
-proto 'prefix:-'    is looser('postfix:++')
+token prefix:sym<->   is looser(&postfix:<++>)    
     is pirop('neg')
     { ... }
 
 ## exponentiation
-proto 'infix:^'     is looser('prefix:-')  { ... }
+token infix:sym<^>    is looser(&prefix:<->)    { ... }
 
 ## multiplicative
-proto 'infix:*'     is looser('infix:^')
+token infix:sym<*>    is looser(&infix:<^>)
     is pirop('mul')
     { ... }
 
-proto 'infix:/'     is equiv('infix:*')
+token infix:sym</>    is equiv(&infix:<*>)
     is pirop('div')
     { ... }
 
-proto 'infix:%'     is equiv('infix:*')
+token infix:sym<%>    is equiv(&infix:<*>)
     is pirop('mod')
     { ... }
 
+
 ## additive
-proto 'infix:+'     is looser('infix:*')
+token infix:sym<+>    is looser(&infix:<*>)
     is pirop('add')
     { ... }
 
-proto 'infix:-'     is equiv('infix:+')
+token infix:sym<->    is equiv(&infix:<+>)
     is pirop('sub')
     { ... }
 
 ## assignment
-proto 'infix:='     is looser('infix:+')
+token infix:sym<=>    is looser(&infix:<+>)
     is assoc('right')
     is past('assign')
     is lvalue(1)
     { ... }
 
 ## relational
+token infix:sym<==>   is looser(&infix:<=>)
+    is assoc('non')
+    {...}
+
 proto 'infix:=='    is looser('infix:=')  is assoc('non')  { ... }
 proto 'infix:!='    is equiv('infix:==') { ... }
 proto 'infix:<'     is equiv('infix:==') { ... }

Added: trunk/languages/abc/src/abc-2a.txt
==============================================================================
--- (empty file)
+++ trunk/languages/abc/src/abc-2a.txt  Wed May 30 10:11:10 2007
@@ -0,0 +1,126 @@
+class ABC::Grammar::ASTBuilder;
+
+## DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
+
+## This is a draft concept of building an abstract syntax
+## tree (using PAST-pm) using methods in a parse tree (abc-2.pg)
+## instead of as a separate TGE parse->PAST phase.  The advantage
+## of this approach is that the conversions are easier to write,
+## as they use a fairly simple subset of Perl 6.
+
+## each method here corresponds to a rule of the same name 
+## in ABC::Grammar.  The method is invoked automatically wherever a 
+## {*} appears in the parse rule.  So, for example, where abc-2.pg
+## has a regex like:
+##
+##     token float { [ \d+ '.' \d* | '.' \d+ ]  {*}  }
+##
+## The 'float' method of this class will be invoked at the point
+## of the {*}, with the current match object in the C< $/ > lexical 
+## variable.  For regexes that have multiple points of invocation,
+## the grammar can specify a $key parameter that is passed to the AST
+## method here.
+##
+## token term {
+##     | <float>                     {*#<float>}
+##     | <integer>                   {*#<integer>}
+##     ...
+## }
+##
+## This is just a draft/concept file at the moment, the actual
+## syntax and operation is likely to change.
+
+
+method TOP { 
+    return $<program>; 
+}
+
+method float {
+    return PAST::Val.new( :node($/), :vtype('.Float'), :name($/) );
+}
+
+method integer {
+    return PAST::Val.new( :node($/), :vtype('.Integer'), :name($/) );
+}
+
+method variable {
+    return PAST::Var.new( :node($/), :name($/), :viviself('.Integer'),
+                          :lvalue($+lvalue) ); 
+}
+
+method term(:$key) {
+    if $key eq 'float'         { return $<float>; }
+    if $key eq 'integer'       { return $<integer>; }
+    if $key eq 'variable'      { return $<variable>; }
+    if $key eq 'array'         { 
+        return PAST::Var.new( $<variable>, $<expression>,
+                              :node($/),
+                              :name($<variable>.text ~ '_array'),
+                              :viviself('.Integer') );
+    }
+    if $key eq 'call'          {
+        return PAST::Op.new( $<expression>,
+                             :node($/),
+                             :name($<variable>.text),
+                             :pasttype('call') );
+    }
+}
+
+method compound_statement {
+    return $<statement_list>;
+}
+
+method if_statement {
+    my $x := PAST::Op.new( $<expression>, $<statement>[0],
+                           :node($/), :pasttype('if') );
+    if ($<statement>[1]) { $x.push($<statement>[1]); }
+    return $x;
+}
+
+method while_statement {
+    return PAST::Op.new( $<expression>, $<statement>,
+                         :node($/), :pasttype('while') );
+}
+
+method for_statement {
+    my $iter := PAST::Stmts.new( $<statement>, $<expression>[2] );
+    my $loop := PAST::Op.new( $<expression>[1], $iter, :pasttype('while') );
+    return PAST::Stmts.new( $<expression>[0], $loop );
+}
+
+method statement(:$key) {
+    if $key eq 'if'            { return $<if_statement>; }
+    if $key eq 'while'         { return $<while_statement>; }
+    if $key eq 'for'           { return $<for_statement>; }
+    if $key eq 'compound'      { return $<compound_statement>; }
+    if $key eq 'expression'    { return $<expression>; }
+}
+
+
+method statement_list {
+    my $stmts := PAST::Stmts.new( :node($/) );
+    for @$<statement> { $stmts.push( $_ ); }
+    return $stmts;
+}
+
+method program {
+    return PAST::Block.new( :node($/), $<statement_list> );
+}            
+
+
+method expression {
+    return $<EXPR>;
+}
+
+
+method EXPR(:$key) {
+    if ($key eq 'reduce') {
+        my $op := PAST::Op.new( :node($/),
+                                :name($<top><category> ~ ':' ~ $<top><sym>),
+                                :pasttype($<top><pasttype>),
+                                :pirop($<top><pirop>),
+                                :returns($<top><returns>) );
+        foreach @$/ { $op.push($/); }
+        return $op;
+    }
+}

Reply via email to