147 lines
4.0 KiB
C#
147 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace ShintenScript
|
|
{
|
|
public class Parser
|
|
{
|
|
protected readonly Lexer lexer;
|
|
|
|
public Parser(Lexer lexer)
|
|
{
|
|
this.lexer = lexer;
|
|
}
|
|
|
|
public IASTNode ParseExpression()
|
|
{
|
|
if (lexer.Accept(Token.Type.SEMICOLON))
|
|
{
|
|
lexer.Pop();
|
|
return new ASTNodeLiteral(null);
|
|
}
|
|
|
|
return ParseExpressionAssignLevel();
|
|
}
|
|
|
|
public IASTNode ParseExpressionAssignLevel()
|
|
{
|
|
IASTNode lhs = ParseExpressionComparisonLevel();
|
|
|
|
return lhs;
|
|
}
|
|
|
|
public IASTNode ParseExpressionComparisonLevel()
|
|
{
|
|
List<IASTNode> nodes = new List<IASTNode>();
|
|
List<Token.Type> comparisons = new List<Token.Type>();
|
|
|
|
nodes.Add(ParseExpressionAdditiveLevel());
|
|
|
|
while (lexer.Accept(Token.Type.EQ, Token.Type.NE, Token.Type.LT, Token.Type.GT, Token.Type.LE, Token.Type.GE))
|
|
{
|
|
comparisons.Add(lexer.Pop().type);
|
|
nodes.Add(ParseExpressionAdditiveLevel());
|
|
}
|
|
|
|
if (nodes.Count == 1)
|
|
return nodes[0];
|
|
|
|
return new ASTNodeComparison(nodes, comparisons);
|
|
}
|
|
|
|
public IASTNode ParseExpressionAdditiveLevel()
|
|
{
|
|
IASTNode lhs = ParseExpressionMultiplicativeLevel();
|
|
|
|
if (lexer.Accept(Token.Type.PLUS, Token.Type.MINUS))
|
|
{
|
|
bool isAddition = lexer.Pop().type == Token.Type.PLUS;
|
|
IASTNode rhs = ParseExpressionAdditiveLevel();
|
|
|
|
if (isAddition)
|
|
return new ASTNodeAdd(lhs, rhs);
|
|
else
|
|
return new ASTNodeSubtract(lhs, rhs);
|
|
}
|
|
|
|
return lhs;
|
|
}
|
|
|
|
public IASTNode ParseExpressionMultiplicativeLevel()
|
|
{
|
|
IASTNode lhs = ParseExpressionWithPrefix();
|
|
|
|
if (lexer.Accept(Token.Type.ASTERISK, Token.Type.SLASH))
|
|
{
|
|
bool isMultiplication = lexer.Pop().type == Token.Type.ASTERISK;
|
|
IASTNode rhs = ParseExpressionMultiplicativeLevel();
|
|
|
|
if (isMultiplication)
|
|
return new ASTNodeMultiply(lhs, rhs);
|
|
else
|
|
return new ASTNodeDivide(lhs, rhs);
|
|
}
|
|
|
|
return lhs;
|
|
}
|
|
|
|
public IASTNode ParseExpressionWithPrefix()
|
|
{
|
|
if (lexer.Accept(Token.Type.PLUS))
|
|
lexer.Pop();
|
|
|
|
if (lexer.Accept(Token.Type.MINUS))
|
|
{
|
|
lexer.Pop();
|
|
return new ASTNodeNegative(ParseExpressionPrimary());
|
|
}
|
|
|
|
return ParseExpressionPrimary();
|
|
}
|
|
|
|
public IASTNode ParseExpressionPrimary()
|
|
{
|
|
if (lexer.Accept(Token.Type.NUMBER))
|
|
return new ASTNodeLiteral(lexer.Pop().data);
|
|
|
|
if (lexer.Accept(Token.Type.LPAREN))
|
|
return ParseExpressionParenthesised();
|
|
|
|
if (lexer.Accept(Token.Type.LBRACE))
|
|
return ParseBlock();
|
|
|
|
throw new ParsingException("Expected expression");
|
|
}
|
|
|
|
public IASTNode ParseExpressionParenthesised()
|
|
{
|
|
lexer.Expect(Token.Type.LPAREN);
|
|
IASTNode expression = ParseExpression();
|
|
lexer.Expect(Token.Type.RPAREN);
|
|
return expression;
|
|
}
|
|
|
|
public IASTNode ParseBlock()
|
|
{
|
|
lexer.Expect(Token.Type.LBRACE);
|
|
|
|
List<IASTNode> statements = new List<IASTNode>();
|
|
|
|
while (!lexer.Accept(Token.Type.RBRACE))
|
|
{
|
|
statements.Add(ParseExpression());
|
|
}
|
|
|
|
lexer.Pop();
|
|
|
|
if (statements.Count == 0)
|
|
return new ASTNodeLiteral(null);
|
|
|
|
return new ASTNodeBlock(statements);
|
|
}
|
|
}
|
|
}
|