1

I have created a simple grammar for a language I have decided to call SWL:

grammar swl;

program   : 'begin' statement+ 'end';

statement : assign | add | sub | mul | div | print | whilecond | ifcond ;
condition : expr ;
expr      : '(' expr ')' | expr 'and' expr | expr 'or' expr | 'not' expr | expr '=' expr | expr '>=' expr | expr '<=' expr | expr '>' expr | expr '<' expr | ID | NUMBER;

assign    : 'let' ID 'be' (NUMBER | ID) ;
print     : 'print' (NUMBER | ID) ;

add       : 'add' (NUMBER | ID) 'to' ID ;
sub       : 'sub' (NUMBER | ID) 'to' ID ;
mul       : 'mul' (NUMBER | ID) 'to' ID ;
div       : 'div' (NUMBER | ID) 'to' ID ;

whilecond : 'while (' condition ') do' statement+ 'stop' ;

ifcond    : 'if (' condition ') then' statement+ 'stop' | 'if (' condition ') then' statement+ 'else' statement+ 'stop' ;

ID        : [a-z]+ ;
NUMBER    : [0-9]+ ;
WS        : [ \n\t]+ -> skip;
ErrorChar : . ;

I am a bit in trouble with the ifcond. Given this SWL program:

begin
    if (not(a > 1) or (c <= b)) then
     mul 5 to k
    stop
end

I am able to get this C++ output:

#include <iostream>

using namespace std;

int main() {
    if ( !(a>1) || (c<=b)) {
    k *= 5;
    }
}

This is great! By the way with the following input:

begin
    if (not(a > 1) or (c <= b)) then
     mul 5 to k
    else
     mul 15 to k
    stop
end

I have this output:

#include <iostream>

using namespace std;

int main() {
    if ( !(a>1) || (c<=b)) {
    k *= 5;
    k *= 15;
    }
}

As you can see the second example is missing the else statement part. What is wrong? Do I have to change the ifcond grammar and add another rule/variable? This is the MyListner.cpp file.

void fixString(string& cond) {

    size_t pos = cond.find("and", 0);
    if (pos != string::npos) { cond.replace(pos, 3, " && "); }

    pos = cond.find("or", 0);
    if (pos != string::npos) { cond.replace(pos, 2, " || "); }

    pos = cond.find("not", 0);
    if (pos != string::npos) { cond.replace(pos, 3, " !"); }

}

void MyListener::enterIfcond(swlParser::IfcondContext *ctx) {
    string cond = ctx->condition()->getText();
    fixString(cond);

    cout << string(indent, ' ') << "if (" << cond << ") {" << endl;
}

void MyListener::exitIfcond(swlParser::IfcondContext *ctx) {
    cout << string(indent, ' ') << "}" << endl;
}

My suspect is that the grammar is not good enough and I'd need another variable to call the else part. I don't know how to fix this issue, any idea?

Ivan Kochurkin
  • 4,413
  • 8
  • 45
  • 80
Emma Rossignoli
  • 935
  • 7
  • 25
  • I suspect the problem is in your listener, not in the grammar. – Jiri Tousek May 03 '18 at 08:02
  • It's unusual to have spaces inside tokens, like in `') then'`. That means that there must be exactly one space between `)` and `then`. If you write `')' 'then'` instead, it could be 0 or more spaces or, for example, a newline, which is way more flexible. – sepp2k May 05 '18 at 12:49

1 Answers1

0

The ifcond is fine but it would be easier if you added another variable before the else so that you can use the exit method of the listener. Use this:

ifelsecond: ifcond | statement ;
ifcond    : 'if (' condition ') then' statement+ 'stop' | 'if (' condition ') then' ifelsecond+ 'else' statement+ 'stop' ;

Now you can easily edit MyListner.cpp like this:

void MyListener::enterIfcond(swlParser::IfcondContext *ctx) {
    string cond = ctx->condition()->getText();
    fixString(cond);

    cout << "\n" << string(indent, ' ') << "if (" << cond << ") {" << endl;
}

void MyListener::exitIfcond(swlParser::IfcondContext *ctx) {
    cout << string(indent, ' ') << "}\n" << endl;
}

void MyListener::exitIfelsecond(swlParser::IfelsecondContext *ctx) {
    cout << string(indent, ' ') << "} else {" << endl;
}

You grammar is good but you are using a not really needed production that makes the listener code harder to write. Since you are using the stop you don't have the dangling else issue.

The solution I have given may not be the best but it works because the grammar is not ambiguous because of the "scoped" statements that are enclosed inside something (in your case then and stop).

Alberto Miola
  • 4,643
  • 8
  • 35
  • 49