b3b00 / csly

a C# embeddable lexer and parser generator (.Net core)
MIT License
366 stars 33 forks source link

Issue in math operation using getting-started example #354

Closed suran closed 1 year ago

suran commented 1 year ago

I am trying to use csly to create a calculator. First I need is to cover basic math. I altered your example from url: https://github.com/b3b00/csly/wiki/getting-started to show my issue, I just changed it to do subtraction instead of addition and discovered an issue.

10 - 5 == 5 // ok 10 - 5 - 4 == 9 // should be 1 10 - 5 - 4 - 0 - 1 === 10 // should be 0

In another test(code not provided) I also tried division and discovered the same issue with division 81 / 3 / 3 == 81 // should be 9 81 / 3 / 9 = 243 // should be 3

The result is in line with the SyntaxTree provided in the result, but the tree and the result are not in line with math rules. I am not sure if the issue is on your side or I have to implement that by myself.

My code:

public enum ExpressionToken {
    [Lexeme("[0-9]+")]
    INT = 1,

    [Lexeme("\\-")]
    MINUS = 2,

    [Lexeme("[ \\t]+", isSkippable: true)] // the lexeme is marked isSkippable : it will not be sent to the parser and simply discarded.
    WS = 3
}

public class ExpressionParser {
    [Production("expression: INT")]
    public int intExpr(Token<ExpressionToken> intToken) {
        return intToken.IntValue;
    }

    [Production("expression: term MINUS expression")]
    public int Expression(int left, Token<ExpressionToken> operatorToken, int right) {
        return left - right;
    }

    [Production("term: INT")]
    public int Expression(Token<ExpressionToken> intToken) {
        return intToken.IntValue;
    }
}

public class Calculator { public int Evaluate(string expression) { var parserInstance = new ExpressionParser(); var builder = new ParserBuilder<ExpressionToken, int>(); var parser = builder.BuildParser(parserInstance, ParserType.LL_RECURSIVE_DESCENT, "expression").Result; var r = parser.Parse(expression); return (int)r.Result; } }

b3b00 commented 1 year ago

The getting started uses a BNF parser that produces a right associative expression. This is natural as recursive descent parser (and CSLY is one) can not use left recursive grammar (see https://github.com/b3b00/csly/wiki/LeftRecursion). So 10 - 5 - 4 is seen as 10 - ( 5 - 4 ) == 10 - 1= 9

But CSLY offerts a way to easily manage expression parsing : https://github.com/b3b00/csly/wiki/expression-parsing

And you can find a complete example here : https://github.com/b3b00/csly/tree/dev/samples/SimpleExpressionParser