namespace Amogulator.Suslang; public class Parser { private string text; private Lexer lexer; private Token currentToken; public Parser(string text, Lexer lexer) { this.text = text; this.lexer = lexer; this.currentToken = this.lexer.next(); } public Expr parseExpr() { return parsePrec11(); } public Expr parsePrec11() { var left = parsePrec12(); if (!done() && current().type == TokenType.Plus) { step(); var right = parsePrec11(); return new BinaryExpr() { type = BinaryType.Add, left = left, right = right, }; } else if (!done() && current().type == TokenType.Minus) { step(); var right = parsePrec11(); return new BinaryExpr() { type = BinaryType.Subtract, left = left, right = right, }; } else { return left; } } public Expr parsePrec12() { var left = parsePrec13(); if (!done() && current().type == TokenType.Asterisk) { step(); var right = parsePrec12(); return new BinaryExpr() { type = BinaryType.Multiply, left = left, right = right, }; } else if (!done() && current().type == TokenType.Slash) { step(); var right = parsePrec12(); return new BinaryExpr() { type = BinaryType.Divide, left = left, right = right, }; } else if (!done() && current().type == TokenType.Percent) { step(); var right = parsePrec12(); return new BinaryExpr() { type = BinaryType.Modulo, left = left, right = right, }; } else { return left; } } public Expr parsePrec13() { return parsePrec18(); } public Expr parsePrec18() { if (!done() && current().type == TokenType.LParen) { step(); var expr = parseExpr(); if (done() || current().type != TokenType.RParen) { var pos = position(); step(); return new ErrorExpr() { position = pos, message = "expected ')'" }; } step(); return expr; } else { return parseOperand(); } } public Expr parseOperand() { var start = position(); if (done()) { step(); return new ErrorExpr() { position = start, message = "expected value, got Eof", }; } else if (current().type == TokenType.Int) { var intToken = current(); step(); if (!done() && current().type == TokenType.Decimal) { var decimalToken = current(); step(); return new FloatExpr() { value = double.Parse(this.text.Substring(start.index, intToken.length + decimalToken.length).Replace(".", ",")), }; } else { return new IntExpr() { value = int.Parse(this.text.Substring(start.index, intToken.length)), }; } } else if (current().type == TokenType.Decimal) { var decimalToken = current(); step(); return new FloatExpr() { value = double.Parse("0" + this.text.Substring(start.index, decimalToken.length).Replace(".", ",")), }; } else if (current().type == TokenType.String) { var stringToken = current(); step(); return new StringExpr() { value = this.text.Substring(start.index, stringToken.length), }; } else if (current().type == TokenType.False) { step(); return new BoolExpr() { value = false, }; } else if (current().type == TokenType.True) { step(); return new BoolExpr() { value = true, }; } else { step(); return new ErrorExpr() { position = start, message = "expected value", }; } } private Position position() => current().position; private Token current() => this.currentToken; private bool done() => this.currentToken.type == TokenType.Eof; private void step() { this.currentToken = this.lexer.next(); } }