-1

Im working on a UNI project and we have to develop a programming language from scratch. We use antlr4 to generate the parse tree. I'm currently working on getting a for loop to work, I have the grammar and can take the values out. My current problem is how to loop the statements in the body of the for loop.

Here is my grammar:

grammar LCT;
program: stmt*;
stmt: assignStmt
    | invocationStmt
    | show
    | forStatement
;

assignStmt: VAR ID '=' expr;

invocationStmt: name=ID ((expr COMMA)* expr)?;

expr: ID | INT | STRING;

show: 'show' (INT | STRING | ID);

block : '{' statement* '}' ;

statement : block
           | show
           | assignStmt
;

forStatement : 'loop' ('(')? forConditions (')')? statement* ;
forConditions : iterator=expr  'from' startExpr=INT range='to' endExpr=INT ;


//tokens
COMMA: ',';
VAR: 'var';
INT: [0-9]+;
STRING: '"' (~('\n' | '"'))* '"';
ID: [a-zA-Z_] [a-zA-Z0-9_]*;

WS: [ \n\t\r]+ -> skip;

And this is the current listener that supports assigning and printing ints

package LCTlang;

import java.util.HashMap;

public class LCTCustomBaseListener extends LCTBaseListener {

    HashMap<String, Integer> variableMap = new HashMap();
    String[] keyWords = {"show", "var"};



    @Override public void exitAssignStmt(LCTParser.AssignStmtContext ctx) {
        this.variableMap.put(ctx.ID().getText(),
                Integer.parseInt(ctx.expr().getText()));
    }


    @Override public void exitInvocationStmt(LCTParser.InvocationStmtContext ctx) {
        this.variableMap.put(ctx.name.getText(),
                Integer.parseInt(ctx.ID().getText()));
    }

    @Override
    public void exitShow(LCTParser.ShowContext ctx) {
        if(ctx.INT() != null) {
            System.out.println(ctx.INT().getText());
        }
        if(ctx.STRING() != null) {
            System.out.println(ctx.ID().getText());
        }
        else if(ctx.ID() != null) {
            System.out.println(this.variableMap.get(ctx.ID().getText()));
        }
    }

    @Override public void exitForStatement(LCTParser.ForStatementContext ctx) {
        int start = Integer.parseInt(ctx.forConditions().startExpr.getText());
        int end = Integer.parseInt(ctx.forConditions().endExpr.getText());
        String varName = ctx.forConditions().iterator.getText();
        int i;

        for (i = start; i < end; i++) {
            for (LCTParser.StatementContext state : ctx.statement()){
                System.out.println(state);
            }
        }
    }
}

My problem is in the looping of the statements, and how that is done.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
Wrafttex
  • 13
  • 4
  • This Q&A shows `if` and `while` statements suitable for a school project (the `while` statement should be similar to how a `for` statement works): https://stackoverflow.com/questions/15610183/if-else-statements-in-antlr-using-listeners – Bart Kiers Apr 06 '21 at 10:33

1 Answers1

0

A listener is going to be a poor choice for execution. You've turned the tree navigation over to a Tree Walker (hitting each node only once), that calls you back when it encounters nodes you're interested in. You won't convince it to walk the children nodes of some iteration node (while, for, etc.) more than once, and that's pretty much the point of iteration structures. It won't detect that a node is a call to a function and then navigate to that function. It's JUST walking through the ParseTree.

For some, fairly simple grammars (usually something like an expression evaluator (maybe a calculator), you could set up a visitor that returns whatever your expression datatype is (probably a Float for a calculator).

In your case, I'd suggest that ANTLR has provided its value. It's a Parser and has provided a ParseTree for you. Now it's up to you to write code that utilizes that parse tree to execute the functionality. You're now in the world of creating a runtime for your language. Thank ANTLR for making it easy to parse, and providing nice error messages and robust error recovery.

To execute your logic, you'll need to write code that uses those data structures, keeps up with the current value of variables, and, based on those values, decides to execute everything contained in that for/while/... loop. You'll have similar runtime work to evaluate boolean expressions to decide whether to execute children in if/else statements, etc. This runtime will also have to keep up with call stacks of functions calling other functions, etc. In short, executing your resulting logic will involve referencing the parsed input, but won't particularly look like navigating your parse Tree.

(Note: many people find a full parse tree to be a bit tedious to navigate (it tends to have a lot of intermediate nodes). In the past, I've written a Visitor to produce something more like an AST (Abstract Syntax Tree). It's a trimmed down tree that has the structure I want for further processing. This is not necessarily required, but you may find it easier to work with.)

Mike Cargal
  • 6,610
  • 3
  • 21
  • 27