156 lines
4.7 KiB
C#
156 lines
4.7 KiB
C#
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();
|
|
}
|
|
}
|