I'm trying to write a toy BASIC to assembler. Here's my code so far:

grammar G {
        rule TOP        { <stmts> }
        rule stmts      { <statement>* }
        rule statement  { <print-stmt> | <for-loop> | <assign> }
        rule print-stmt { 'print' <expr> }
        rule for-loop   { 'for' <var> '=' <expr> 'to' <expr>  <stmts> 'next' }
        rule assign     { <var> '=' <expr> }

        token var       { <[a..z]>+   }
        rule expr       { <expr-p> ('+' <expr-p>)* }
        rule expr-p     { <num> | <var> }
        token num       { <[0..9]>+ }
}

my $input = slurp;

#my $m = G.parse($input);
#say $m;

# print the prologue
say  Q [
@ Automatically-generated assembler code
.global main
main:
        @ entry point
        push    {ip, lr}
];


# exit and cleanup before we start putting out data
my $bye = Q [
        @ exit and cleanup
        mov     r0, #0 @ return value 0
        pop     {ip, pc}
];

sub write-varnames($vnames) {

        say "TODO";
        say $vnames.keys.sort;
}


class A {
        has $.varnames = SetHash.new;

        method TOP ($/) { say "TOP"; say $bye; write-varnames $.varnames ; }         method var ($/) { my $vname = $/.Str ; say $vname ; $.varnames{"$vname"}++ ; }
}

my $acts = A.new;
my $ma = G.parse($input, :actions($acts));


And here's a simple test program:

for i = 1 to 3+2
        sum = sum + i
next

print sum

The problem is that 'next' is taken to be a variable name, I think, as evidenced when write-varnames is run:

(i next sum)

I guess one way around all this is never to let assignment start with a variable name, but demand a 'let' in for assignment, as is

    let sum = sum + i

But I'm wondering, is there a way to write token var in such a way that it matches <[a..z]>+ EXCEPT when it is a keyword (print, for, to, next, etc.)?

Is there a generally accepted way of doing all this, like defining the keywords as seperate tokens, for example?

Reply via email to