Help with If/then/else

Sep 22, 2015 at 9:27 AM
I have the follow grammar/langauge example (a subset of the Informix ACE Reporting Langauage), because of the syntax of the single and multi if/else combination I'm getting conflicts.
Can any body help?


FORMAT_SECTION

// Single Line IF
IF expression THEN
STATEMENT

// Single Line IF/ELSE
IF expression THEN
STATEMENT
ELSE
STATEMENT
// Multi Line IF
IF expression THEN
BEGIN
STATEMENT
STATEMENT
STATEMENT
END

// Multi Line IF / Single Line Else
IF expression THEN
BEGIN
STATEMENT
STATEMENT
STATEMENT
END
ELSE
STATEMENT

// Single Line IF / Multi Line ELSE
IF expression THEN
STATEMENT
ELSE
BEGIN
STATEMENT
STATEMENT
STATEMENT
END

// Multi Line IF / Multi Line ELSE
IF expression THEN
BEGIN
STATEMENT
STATEMENT
STATEMENT
END
ELSE
BEGIN
STATEMENT
STATEMENT
STATEMENT
END


END // END OF FORMAT_SECTION
Sep 22, 2015 at 11:08 AM
Edited Sep 22, 2015 at 11:13 AM
Concrete help can't really be provided until you post the grammar (Irony, not the language one)

Sounds like the classic dangling else problem, which causes a shift-reduce conflict in LALR parsers like Irony. If this is the case then shift would be the correct action, so insert a PreferShiftHere() after the if in the if-else construct:
Statements.Rule = Statement | "begin" + StatementList + "end"
ifelse.Rule = "if" + Expr + "then"  + Statements + PreferShiftHere() + "else" + Statements + "end"
Sep 22, 2015 at 1:01 PM
Edited Sep 22, 2015 at 1:03 PM
Ok I get the idea of your syntax but can't parse a single line if
IF EXPR THEN
STATEMENT


Below is my grammar
        /////////////////////////////////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////////////////////////////////
        // FORMAT SECTION
        //

        ParExprSingle.Rule = Empty |  ("[" + intNumber + "]") | ("[" + intNumber +"," + intNumber  + "]");
        EXPR.Rule = number | variable | FUN_CALL | stringLiteral | BINARY_EXPR | "(" + EXPR + ")" | UNARY_EXPR;
        BINARY_EXPR.Rule = EXPR + BINARY_OP + EXPR;
        UNARY_EXPR.Rule = SIGN + EXPR;
        SIGN.Rule = ToTerm("-") | "+";
        ASSIGN_STMT.Rule = LET + VARIABLE_OR_FUNCTION_EXPR + "=" + EXPR;

        FUN_CALL.Rule = variable + PreferShiftHere() + "(" + ARG_LIST + ")";
        VARIABLE_OR_FUNCTION_EXPR.Rule = variable | FUN_CALL;

        BINARY_OP.Rule = ToTerm("+") | "^" | "-" | "*" | "/" | "=" | "<=" | ">=" | "<" | ">" | "<>" | "and" | "or" | "matches";


        RegisterOperators(60, "^");
        RegisterOperators(50, "*", "/");
        RegisterOperators(40, "+", "-");
        RegisterOperators(30, "=", "<=", ">=", "<", ">", "<>");
        RegisterOperators(20, "and", "or","matches");

        EXPR_LIST.Rule = MakeStarRule(EXPR_LIST, EXPR);

        ARG_LIST.Rule = MakePlusRule(ARG_LIST, comma, EXPR);
        STATEMENT_LIST.Rule = MakePlusRule(STATEMENT_LIST, STATEMENT);


        // IF / ELSE OPTIONAL COMPOUND
        var STATEMENTS = new NonTerminal("STATEMENTS");
        var IFELSE = new NonTerminal("ifelse");
        STATEMENTS.Rule = STATEMENT | "begin" + STATEMENT_LIST + "end";


        var ELSE = new NonTerminal("ELSE");
        ELSE.Rule = Empty | PreferShiftHere() + "else" + STATEMENTS + "end"; 



        IFELSE.Rule = "if" + EXPR + "then" + STATEMENTS + ELSE;


        // A statement can be one of a number of types
        STATEMENT.Rule = ASSIGN_STMT | PRINT_STMT | /*FOR_STMT_MULTI |*/ NEED_STMT | SKIP_STMT | SKIP_PAGE_STMT;

        NEED_STMT.Rule = ToTerm("NEED") + intNumber + "Lines";
        SKIP_STMT.Rule = ToTerm("Skip ") + intNumber + "Lines";
        SKIP_PAGE_STMT.Rule = "Skip" + "to" + "top" + "of" + "page";


        PRINT_STMT.Rule = ToTerm("print") + PRINT_LIST;
        PRINT_LIST.Rule = MakeStarRule(PRINT_LIST, null, PRINT_ARG);
        PRINT_ARG.Rule = EXPR;

        LINE_CONTENT_OPT.Rule = Empty | IFELSE | STATEMENT_LIST;

        ON_EVERY_RECORD.Rule = Empty | "ON EVERY RECORD" + LINE_CONTENT_OPT;


        //formatSection.Rule = "FORMAT" + AFTER_GROUP_OF +  ON_EVERY_RECORD + END;
        formatSection.Rule = "FORMAT" +  ON_EVERY_RECORD + "end";
        //
        /////////////////////////////////////////////////////////////////////////////////////////////
Sep 22, 2015 at 2:17 PM
This is sample code I'm trying to parse, seems after the first statement the parsers fails when if hits the first IF statement.

FORMAT

LET conlab = "N"
IF dtunit = "QUANT" THEN LET conlab = "Y"
IF dtunit = "QWERTY" THEN LET conlab = "Y"
IF dtunit = "BLUM" THEN LET conlab = "Y"
IF dtunit[10] = "D" THEN LET conlab = "Y"
IF dtprod[1,2] = "HA" THEN LET conlab = "Y"

LET dat=today


IF conlab = "Y" AND dtassy <> "99999.0"
    THEN
    BEGIN
  PRINT hdline01,1 SPACES,"Del: ",hdreqd
  PRINT ""
  PRINT "Order Num.: ",hdorn,2 SPACES, "Prod Code.:",dtprod
  PRINT "Their Ref.: ",hdcord
  PRINT ""
  PRINT "Prod Desc.: ",dtdesc
  PRINT ""
  PRINT "Qty Ordered ",dtoqty USING "---&",
        " Label Number 1 of 1  "
  PRINT ""
  LET pflag = 1
  END

  ELSE

        IF conlab = "N" AND dtassy <> "999999.0"
    THEN
    BEGIN
    FOR lcount = 1 to dtoqty
    DO
    BEGIN
  PRINT hdline01,1 SPACES,"Del: ",hdreqd
  PRINT ""
  PRINT "Order Num.: ",hdorn,2 SPACES, "Prod Code.:",dtprod
  PRINT "Their Ref.: ",hdcord
  PRINT ""
  PRINT "Prod Desc.: ",dtdesc
  PRINT ""
  PRINT "Qty Ordered ",dtoqty USING "---&",
        " Label Number   ",lcount USING "---&","   Of ",
        dtoqty USING "--&"
  PRINT ""
  LET pflag = 1
    END
END

END
Sep 22, 2015 at 2:20 PM
I've strimmed the code done to it's basic level just to process statments and if's
So even with this code I have Shift-reduce conflict. State S6, lookaheads [LET PRINT]. Selected shift as preferred action.
I'm at a loss it make be this because of these 2 lines to add multi code lines?
        var LINES = new NonTerminal("LINES");
        LINES.Rule = MakePlusRule(LINES, LINE);
////////////////////////////////////////////////////////////////////////////////////////////////
        var EXPR = new NonTerminal("EXPRESSION");
        var number = new NumberLiteral("number");
        var stringLiteral = new StringLiteral("String_Literal", "\"", StringOptions.AllowsDoubledQuote);
        var variable = new IdentifierTerminal("Variable");
        var BINARY_EXPR = new NonTerminal("BINARY_EXPR");
        var BINARY_OP = new NonTerminal("BINARY_OP", "operator");
        var UNARY_EXPR = new NonTerminal("UNARY_EXPR");
        var SIGN = new NonTerminal("SIGN");
        var ASSIGN_STMT = new NonTerminal("ASSIGN_STMT");
        var STATEMENT_LIST = new NonTerminal("STATEMENT_LIST");
        var PRINT_STMT = new NonTerminal("PRINT_STMT");
        var PRINT_ARG = new NonTerminal("PRINT_ARG");
        var LET = ToTerm("LET");
        var EXPR_LIST = new NonTerminal("EXPRESSION_LIST");
        var ARG_LIST = new NonTerminal("ARG_LIST");
        var comma = ToTerm(",");
        var STATEMENT = new NonTerminal("STATEMENT");
        var PRINT_LIST = new NonTerminal("PRINT_LIST");
        var LINE_CONTENT = new NonTerminal("LINE_CONTENT");
        var END = ToTerm("END");
        var STATEMENTS = new NonTerminal("STATEMENTS");
        var IF = new NonTerminal("IF");
        var ELSE = new NonTerminal("ELSE");



        EXPR.Rule = number | variable | stringLiteral | BINARY_EXPR | "(" + EXPR + ")" | UNARY_EXPR;
        BINARY_EXPR.Rule = EXPR + BINARY_OP + EXPR;
        UNARY_EXPR.Rule = SIGN + EXPR;
        SIGN.Rule = ToTerm("-") | "+";
        ASSIGN_STMT.Rule = LET + variable + "=" + EXPR;


        BINARY_OP.Rule = ToTerm("+") | "^" | "-" | "*" | "/" | "=" | "<=" | ">=" | "<" | ">" | "<>" | "and" | "or" | "matches";


        RegisterOperators(60, "^");
        RegisterOperators(50, "*", "/");
        RegisterOperators(40, "+", "-");
        RegisterOperators(30, "=", "<=", ">=", "<", ">", "<>");
        RegisterOperators(20, "and", "or", "matches");

        EXPR_LIST.Rule = MakeStarRule(EXPR_LIST, EXPR);

        ARG_LIST.Rule = MakePlusRule(ARG_LIST, comma, EXPR);
        STATEMENT_LIST.Rule = MakePlusRule(STATEMENT_LIST, STATEMENT);

        // IF / ELSE OPTIONAL COMPOUND
        STATEMENTS.Rule = STATEMENT | "BEGIN" + STATEMENT_LIST + "END";



        //ELSE.Rule = Empty | PreferShiftHere() + "ELSE" + STATEMENTS;
        IF.Rule = "if" + EXPR + "then" + STATEMENTS + PreferShiftHere() + "else" + STATEMENTS + "end";


        // A statement can be one of a number of types
        STATEMENT.Rule = ASSIGN_STMT | PRINT_STMT; 

        PRINT_STMT.Rule = ToTerm("PRINT") + PRINT_LIST;
        PRINT_LIST.Rule = MakeStarRule(PRINT_LIST, null, PRINT_ARG);
        PRINT_ARG.Rule = EXPR;

        LINE_CONTENT.Rule = IF | STATEMENT_LIST;

        var LINE = new NonTerminal("LINES");
        LINE.Rule =  LINE_CONTENT;

        var LINES = new NonTerminal("LINES");
        LINES.Rule = MakePlusRule(LINES, LINE);

        this.Root = LINES;
Coordinator
Sep 22, 2015 at 7:02 PM
I don't see where are delimiters (NewLine) ? You should put them in your grammar rules, most likely as extra parameter in MakePlusRule calls for Statements, StatementList nonterminals. Another thing, might be related to conflict - LINE and LINE_CONTENT are equivalent, get rid of one of them, duplicates like these can cause conflicts
Sep 23, 2015 at 7:54 AM
Edited Sep 23, 2015 at 3:26 PM
Hi Roman
I forgot to mention, excellent work. Just wish there was a little more docs. :)
This work to an extent, but I throws an error when I leave a blank line bewteen a statement?
IF slrepcode = "ACB" THEN
BEGIN
  LET rep = "ANDREW COUSENS BEDROOM SALES        "
  LET acb = stot
!!!! < BLANK LINE> !!!!
  LET tbs = tbs+stot
END  
IF slrepcode = "ACD" THEN
BEGIN
  LET rep = "ANDREW COUSENS DIY SALES            "
  LET acd = stot
  LET tds = tds+stot
END
        EXPR_LIST.Rule = MakeStarRule(EXPR_LIST, EXPR);
        ARG_LIST.Rule = MakePlusRule(ARG_LIST, comma, EXPR);
        ASSIGN_STMT.Rule = LET + variable + "=" + EXPR;

        STATEMENT_LIST.Rule = MakePlusRule(STATEMENT_LIST, NewLine, STATEMENT);

        STATEMENTS.Rule = STATEMENT |  "BEGIN" + NewLine + STATEMENT_LIST + NewLine + "END" + NewLine;

        ELSE.Rule = Empty | PreferShiftHere() + "else" + NewLine + STATEMENTS;

        IF.Rule = "if" + EXPR + optionalLF+ "then" + NewLine + STATEMENTS + ELSE;            

        STATEMENT.Rule = ASSIGN_STMT | PRINT_STMT | IF ; 

        LINE_CONTENT.Rule = Empty | STATEMENT_LIST + NewLine;

        var LINES = new NonTerminal("LINES");
        LINES.Rule = MakePlusRule(LINES, NewLine,  LINE_CONTENT);


        this.Root = LINES;
Coordinator
Sep 24, 2015 at 8:07 AM
that's because STATEMENT definition does not allow an empty line as a statement. I line-based languages, an empty line is an (Empty) statement, and it should be in the rules.
Add it there
Marked as answer by Normski99 on 9/24/2015 at 7:14 AM
Sep 24, 2015 at 3:15 PM
Edited Sep 24, 2015 at 3:16 PM
Thanks Roman that worked, I've almost complete the Informix ACE Report grammer.
Last final question I have the following, I need any of theme terms in any order i'm struggle to express this in Irony. Can you advise please.
        ON_EVERY_RECORD.Rule = Empty | "ON EVERY ROW" + LINES;
        ON_EVERY_ROW.Rule = Empty | "ON EVERY ROW" + LINES;
        FIRST_PAGE_HEADER.Rule = Empty | "FIRST PAGE HEADER" + LINES;
        PAGE_TRAILER.Rule = Empty | "PAGE TRAILER" + LINES;
        PAGE_HEADER.Rule = Empty | "PAGE HEADER" + LINES;
        ON_LAST_ROW.Rule = Empty | "ON LAST ROW" + LINES;

        formatSubSection.Rule =    PAGE_HEADER + PAGE_TRAILER + ON_EVERY_RECORD + FIRST_PAGE_HEADER + ON_LAST_ROW;

        formatSection.Rule  =  "FORMAT" + NewLinePlus + formatSubSection + "END" + NewLinePlus;
this.Root = formatSection;

Now an example code syntax would be

FORMAT <- MANDATORY

ON_EVERY_RECORD
statments....

PAGE_HEADER.
statments....

END
Coordinator
Sep 24, 2015 at 5:33 PM
It seems all these headers are just another kind of statement - just add them to Statement definition
Sep 24, 2015 at 5:53 PM
So basically the syntax for is roughly

FORMAT <---- Mandory

ON EVERY ROW <---- Optional Section but only can appear once
STATEMENTS

PAGE HEADER <---- Optional Section but only can appear once
STATMENTS....

AFTER GROUP OF ColumnName <---- Optional Section but only can appear more than once but can't have the same column name
STATMENTS....

END

One interesting fact is that Sections don't have and END terminator but FORMAT does. These sections can appear in any order.
Coordinator
Sep 24, 2015 at 8:41 PM
these kind of things (sections appearing once, etc) are actually more semantic rules - so they should be ignored in grammar rules, but later checked in code, after parsing by running thru syntax tree.
Oct 12, 2015 at 11:54 AM
Thanks I got it working perfectly, I went back to the drawing board and examined the c# syntax closely and I finally contructed the perfect grammar for my ACE Reporting Language.