Basic parser

This commit is contained in:
nub31
2025-01-26 01:55:34 +01:00
parent 8c51c31927
commit 5103593ab4
9 changed files with 166 additions and 18 deletions

View File

@@ -5,8 +5,6 @@ let STD_ERR = 2;
func main() {
write("test");
syscall(SYS_WRITE, STD_OUT, msg);
return 12;
}
func write(msg: void) {

View File

@@ -1,6 +1,6 @@
namespace Nub.Lang.Parsing;
public class BlockNode(IEnumerable<StatementNode> statements) : StatementNode
public class BlockNode(IEnumerable<StatementNode> statements) : Node
{
public IEnumerable<StatementNode> Statements { get; } = statements;
}

View File

@@ -0,0 +1,7 @@
namespace Nub.Lang.Parsing;
public class FuncCallNode(string name, IEnumerable<ExpressionNode> parameters) : StatementNode
{
public string Name { get; } = name;
public IEnumerable<ExpressionNode> Parameters { get; } = parameters;
}

View File

@@ -1,7 +1,8 @@
namespace Nub.Lang.Parsing;
public class FuncDefinitionNode(string name, IEnumerable<FuncParameter> parameters) : DefinitionNode
public class FuncDefinitionNode(string name, IEnumerable<FuncParameter> parameters, BlockNode body) : DefinitionNode
{
public string Name { get; } = name;
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
public BlockNode Body { get; } = body;
}

View File

@@ -0,0 +1,6 @@
namespace Nub.Lang.Parsing;
public class IdentifierNode(string identifier) : ExpressionNode
{
public string Identifier { get; } = identifier;
}

View File

@@ -0,0 +1,6 @@
namespace Nub.Lang.Parsing;
public class LiteralNode(string value) : ExpressionNode
{
public string Value { get; } = value;
}

View File

@@ -15,17 +15,130 @@ public class Parser
public IEnumerable<DefinitionNode> Parse()
{
_index = 0;
List<DefinitionNode> definitions = [];
while (Peek().HasValue)
{
definitions.Add(ParseDefinition());
}
return definitions;
}
private DefinitionNode ParseDefinition()
{
throw new NotImplementedException();
var keyword = ExpectSymbol();
return keyword.Symbol switch
{
Symbol.Let => ParseGlobalVariableDefinition(),
Symbol.Func => ParseFuncDefinition(),
_ => throw new Exception("Unexpected symbol: " + keyword.Symbol)
};
}
private GlobalVariableDefinitionNode ParseGlobalVariableDefinition()
{
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
ExpectSymbol(Symbol.Semicolon);
return new GlobalVariableDefinitionNode(name.Value, value);
}
private FuncDefinitionNode ParseFuncDefinition()
{
var name = ExpectIdentifier();
List<FuncParameter> parameters = [];
ExpectSymbol(Symbol.OpenParen);
if (!TryExpectSymbol(Symbol.CloseParen))
{
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseFuncParameter());
}
}
var body = ParseBlock();
return new FuncDefinitionNode(name.Value, parameters, body);
}
private FuncParameter ParseFuncParameter()
{
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
return new FuncParameter(name.Value, type);
}
private StatementNode ParseStatement()
{
var token = ExpectToken();
switch (token)
{
case IdentifierToken identifier:
{
var symbol = ExpectSymbol();
switch (symbol.Symbol)
{
case Symbol.OpenParen:
{
var parameters = new List<ExpressionNode>();
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseExpression());
TryExpectSymbol(Symbol.Comma);
}
ExpectSymbol(Symbol.Semicolon);
if (identifier.Value == "syscall")
{
return new SyscallNode(parameters);
}
return new FuncCallNode(identifier.Value, parameters);
}
case Symbol.Assign:
throw new NotImplementedException();
default:
throw new Exception($"Unexpected symbol {symbol.Symbol}");
}
}
default:
throw new Exception($"Unexpected token type {token.GetType().Name}");
}
}
private ExpressionNode ParseExpression()
{
var token = ExpectToken();
return token switch
{
LiteralToken literal => new LiteralNode(literal.Value),
IdentifierToken identifier => new IdentifierNode(identifier.Value),
_ => throw new Exception($"Unexpected token type {token.GetType().Name}")
};
}
private BlockNode ParseBlock()
{
ExpectSymbol(Symbol.OpenBrace);
List<StatementNode> statements = [];
while (!TryExpectSymbol(Symbol.CloseBrace))
{
statements.Add(ParseStatement());
}
return new BlockNode(statements);
}
private Type ParseType()
{
var name = ExpectIdentifier();
return new Type(name.Value);
}
private Token ExpectToken()
@@ -36,6 +149,7 @@ public class Parser
throw new Exception("Reached end of tokens");
}
Next();
return token.Value;
}
@@ -46,9 +160,10 @@ public class Parser
{
throw new Exception($"Expected {nameof(SymbolToken)} but got {token.GetType().Name}");
}
return symbol;
}
private void ExpectSymbol(Symbol symbol)
{
var token = ExpectSymbol();
@@ -58,6 +173,13 @@ public class Parser
}
}
private bool TryExpectSymbol(Symbol symbol)
{
var result = Peek() is { HasValue: true, Value: SymbolToken symbolToken } && symbolToken.Symbol == symbol;
if (result) Next();
return result;
}
private IdentifierToken ExpectIdentifier()
{
var token = ExpectToken();
@@ -65,9 +187,10 @@ public class Parser
{
throw new Exception($"Expected {nameof(IdentifierToken)} but got {token.GetType().Name}");
}
return identifier;
}
private LiteralToken ExpectLiteral()
{
var token = ExpectToken();
@@ -75,19 +198,25 @@ public class Parser
{
throw new Exception($"Expected {nameof(LiteralToken)} but got {token.GetType().Name}");
}
return literal;
}
private Optional<Token> Peek()
{
while (_index < _tokens.Length && _tokens[_index] is SymbolToken { Symbol: Symbol.Whitespace })
{
Next();
}
if (_index < _tokens.Length)
{
return _tokens[_index];
}
return Optional<Token>.Empty();
}
private void Next()
{
_index++;

View File

@@ -1,11 +1,6 @@
namespace Nub.Lang.Parsing;
public class ESyscallNode(IEnumerable<FuncParameter> parameters) : ExpressionNode
public class SyscallNode(IEnumerable<ExpressionNode> parameters) : StatementNode
{
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
}
public class SSyscallNode(IEnumerable<FuncParameter> parameters) : StatementNode
{
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
public IEnumerable<ExpressionNode> Parameters { get; } = parameters;
}

View File

@@ -1,6 +1,12 @@
using Nub.Lang.Lexing;
using Nub.Lang.Parsing;
var src = File.ReadAllText(args[0]);
var lexer = new Lexer(src);
var tokens = lexer.Lex();
var tokens = lexer.Lex();
var parser = new Parser(tokens);
var definitions = parser.Parse();
Console.Read();