tlang-compiler/AST.cs

756 lines
26 KiB
C#

using System.Linq;
using System.Collections.Generic;
using System.Text;
namespace TLang
{
public class Parser
{
private static bool _checkForArrayType(ref int i,List<LexToken> tokens)
{
if(i+2 < tokens.Count && tokens[i+1].Type == LexSymbol.Symbol && tokens[i+2].Type == LexSymbol.Symbol && tokens[i+1].TokenText == "[" && tokens[i+2].TokenText == "]")
{
//we are getting somewhere
//type normal parse
//type [ ] normal parse
i+=2;
return true;
}
return false;
}
public static ProgramNode Parse(List<LexToken> tokens)
{
ProgramNode node=new ProgramNode();
//function pointers are
//funcptr func identifer (arg_type arg_name, ...);
//funcptr
// a function can be
// func identifier (arg_type arg_name,...)
// return_type identifier (arg_type arg_name, ...)
// func identifier (arg_type arg_name)
// return_type identifier (arg_type arg_name)
// func identifier ()
// return_type identifier ()
//a const variable can be (also in func)
//variable_type identifier;
//variable_type identifier = expression;
int i = 0;
for(;i<tokens.Count;i++)
{
//we need a type or null
LexToken type_token = tokens[i];
if(type_token.Type == LexSymbol.Keyword || type_token.Type == LexSymbol.Identifier)
{
string type;
//we only allow keywords for variable types for now eg no data types other than system ones
if(_checkForArrayType(ref i,tokens))
{
type=$"{type_token.TokenText}[]";
//it is an array
}else{
type=type_token.TokenText;
//not a bloddy array
}
i++;
if(i<tokens.Count)
{
LexToken name_token = tokens[i];
if(name_token.Type == LexSymbol.Identifier)
{
//this must be an identifier
//now we will check if it is a function or a variable
//is next char ( or = or ;
i++;
if(i<tokens.Count)
{
LexToken del=tokens[i];
if(del.Type == LexSymbol.Symbol)
{
if(del.TokenText == "(")
{
FunctionNode fnode=ParseArguments(ref i,tokens);
ParseFunction(ref i,tokens,fnode);
fnode.Column = type_token.ColumnNumber;
fnode.FilePosition = type_token.OffsetInFile;
fnode.Line = type_token.LineNumber;
fnode.ReturnType = type_token.TokenText;
fnode.Name = name_token.TokenText;
node.Functions.Add(fnode);
//must be function
}else if(del.TokenText == "=")
{
i++;
if(i<tokens.Count){
//must be creation of global variable
var res=ParseExpression(ref i,tokens);
VariableDeclarationNode decl=new VariableDeclarationNode();
decl.Column = type_token.ColumnNumber;
decl.FilePosition = type_token.OffsetInFile;
decl.Line = type_token.LineNumber;
decl.VariableType = type_token.TokenText;
decl.Name = name_token.TokenText;
decl.InitialValue = res;
node.Variables.Add(decl);
}
}else if(del.TokenText == ";")
{
//null global variable
VariableDeclarationNode decl=new VariableDeclarationNode();
decl.Column = type_token.ColumnNumber;
decl.FilePosition = type_token.OffsetInFile;
decl.Line = type_token.LineNumber;
decl.VariableType = type_token.TokenText;
decl.Name = name_token.TokenText;
decl.InitialValue=new UninitNode();
node.Variables.Add(decl);
}
}
}
}
}
}
}
return node;
}
private static FunctionNode ParseArguments(ref int i, List<LexToken> tokens)
{
i++;
List<ArgumentNode> argumentNodes = new List<ArgumentNode>();
//type arg,type arg
for(;i<tokens.Count;i++)
{
LexToken type = tokens[i];
if(type.Type ==LexSymbol.Symbol && type.TokenText == ")")
{
break;
}
if(type.Type == LexSymbol.Keyword || type.Type == LexSymbol.Identifier)
{
//we got a type
ArgumentNode node = new ArgumentNode();
string typestr;
//we only allow keywords for variable types for now eg no data types other than system ones
if(_checkForArrayType(ref i,tokens))
{
typestr=$"{type.TokenText}[]";
//it is an array
}else{
typestr=type.TokenText;
//not a bloddy array
}
node.ArgType=typestr;
i++;
if(i<tokens.Count)
{
LexToken name = tokens[i];
if(name.Type == LexSymbol.Identifier)
{
node.Name = name.TokenText;
argumentNodes.Add(node);
i++;
if(i<tokens.Count)
{
LexToken sep= tokens[i];
if(sep.Type == LexSymbol.Symbol)
{
i++;
if(sep.TokenText == ")")
{
break;
}else if(sep.TokenText == ",")
{
continue;
}
}
}
}
}else{
throw new Exception("argument name expected");
}
}
}
return new FunctionNode(){Arguments=argumentNodes};
}
private static Node ParseStatement(ref int i,List<LexToken> tokens)
{
//if(EXPRESSION) {} else {}
//if(EXPRESSION) {}
//while {}
//break;
//return EXPRESSION;
//TYPE VARNAME = EXPRESSION;
//VARNAME = EXPRESSION;
//FUNCNAME(EXPRESSION,...)
LexToken type_token_keyword_token = tokens[i];
if(type_token_keyword_token.Type == LexSymbol.Symbol && type_token_keyword_token.TokenText == "{")
{
ScopeNode node=new ScopeNode();
i++;
for(;i<tokens.Count;i++)
{
if(tokens[i].TokenText == "}")
{
//i++;
break;
}
node.Nodes.Add(ParseStatement(ref i,tokens));
}
return node;
}else
if(type_token_keyword_token.Type == LexSymbol.Keyword)
{
//its if, while, break or return
if(type_token_keyword_token.TokenText == "break")
{
BreakNode node=new BreakNode();
i++;
return node;
//break
}
else if(type_token_keyword_token.TokenText=="while")
{
i++;
WhileNode node=new WhileNode();
node.Body = ParseStatement(ref i,tokens);
return node;
//while
}
else if(type_token_keyword_token.TokenText == "if")
{
//if
if(i+2<tokens.Count)
{
LexToken lparn = tokens[i+1];
i+=2;
if(lparn.TokenText == "(" && lparn.Type == LexSymbol.Symbol)
{
Expression ifCondition=ParseExpression(ref i,tokens);
LexToken rparn = tokens[i];
if(rparn.TokenText == ")" && rparn.Type == LexSymbol.Symbol)
{
i++;
var truth=ParseStatement(ref i,tokens);
//we need to parse body
}else{
throw new Exception("missing )");
}
}else{
throw new Exception("missing (");
}
}
}
else if(type_token_keyword_token.TokenText == "return")
{
//return
}
else
{
//variable
var type_token=type_token_keyword_token;
string type;
if(_checkForArrayType(ref i,tokens))
{
type=$"{type_token_keyword_token.TokenText}[]";
//it is an array
}else{
type=type_token_keyword_token.TokenText;
//not a bloddy array
}
i++;
if(i<tokens.Count)
{
LexToken name_token = tokens[i];
if(name_token.Type == LexSymbol.Identifier)
{
//this must be an identifier
//now we will check if it is a function or a variable
//is next char ( or = or ;
i++;
if(i<tokens.Count)
{
LexToken del=tokens[i];
if(del.Type == LexSymbol.Symbol)
{
if(del.TokenText == "=")
{
i++;
if(i<tokens.Count){
//must be creation of global variable
var res=ParseExpression(ref i,tokens);
VariableDeclarationNode decl=new VariableDeclarationNode();
decl.Column = type_token.ColumnNumber;
decl.FilePosition = type_token.OffsetInFile;
decl.Line = type_token.LineNumber;
decl.VariableType = type_token.TokenText;
decl.Name = name_token.TokenText;
decl.InitialValue = res;
return decl;
}
}else if(del.TokenText == ";")
{
//null global variable
VariableDeclarationNode decl=new VariableDeclarationNode();
decl.Column = type_token.ColumnNumber;
decl.FilePosition = type_token.OffsetInFile;
decl.Line = type_token.LineNumber;
decl.VariableType = type_token.TokenText;
decl.Name = name_token.TokenText;
decl.InitialValue=new UninitNode();
return decl;
}
}
}
}
}
}
}
throw new Exception("Thrown");
}
private static void ParseFunction(ref int i, List<LexToken> tokens,FunctionNode node)
{
node.Body=ParseStatement(ref i,tokens);
}
private static Expression ParseExpression(ref int i, List<LexToken> tokens)
{
//Console.WriteLine(tokens[i].TokenText);
//an expression can be
//number
//char
//string
//function_call
//bool
//variable
//function call
//method_name(expression ...)
LexToken identifer = tokens[i];
if(identifer.Type == LexSymbol.Integer)
{
i++;
return new ConstInt(identifer.TokenText);
}
if(identifer.Type == LexSymbol.Float)
{
i++;
return new ConstFloat(identifer.TokenText);
}
if(identifer.Type == LexSymbol.Char)
{
i++;
return new ConstChar(identifer.TokenText);
}
if(identifer.Type == LexSymbol.String)
{
i++;
return new ConstString(identifer.TokenText);
}
//either function call or identifer
if(identifer.Type == LexSymbol.Identifier)
{
if(i+1<tokens.Count)
{
var parenToken = tokens[i+1];
if(parenToken.Type == LexSymbol.Symbol)
{
if(parenToken.TokenText == "(")
{
//function_call
List<Expression> args=new List<Expression>();
Console.WriteLine(tokens[i].TokenText);
i+=2;
for(;i<tokens.Count;i++)
{
var exp=ParseExpression(ref i,tokens);
Console.WriteLine(exp);
args.Add(exp);
if(i<tokens.Count)
{
var t = tokens[i];
if(t.Type == LexSymbol.Symbol)
{
if(t.TokenText == ",")
{
continue;
}
if(t.TokenText == ")") {break;}
}
}else{
//error
}
}
i++;
return new FunctionCallNode(identifer.TokenText,args);
}
if(parenToken.TokenText == "[")
{
Expression e=ParseExpression(ref i,tokens);
if(parenToken.Type == LexSymbol.Symbol && parenToken.TokenText == "]")
{
//we got array index
i++;
return new GetArrayValueNode(identifer.TokenText,e);
}
throw new Exception();
//array index;
}
else{
i++;
return new GetVariableValueNode(identifer.TokenText);
}
}else
{
//it is actually a variable
i++;
return new GetVariableValueNode(identifer.TokenText);
}
}else{
//eof
throw new Exception();
}
}
throw new Exception("Error");
}
}
public class WhileNode : Node
{
public override string ToString()
{
return $"While Loop:\n{TabOver(Body.ToString())}";
}
public override NodeType Type {get {return NodeType.While;}}
public Node Body { get; set; }
}
public class BreakNode : Node
{
public override string ToString()
{
return "break loop";
}
public override NodeType Type {get{return NodeType.Break;}}
}
internal class GetVariableValueNode : Expression
{
public string Name {get;set;}
public override NodeType Type {get{return NodeType.GetVariableValue;}}
public override string ToString()
{
return $"Get value from {Name}";
}
public GetVariableValueNode(string tokenText)
{
Name= tokenText;
}
}
public class GetArrayValueNode : Expression
{
public override string ToString()
{
return $"GetArrayValue:\nName: {Name}\nIndex:\n{TabOver(Index.ToString())}";
}
public GetArrayValueNode(string name,Expression expression)
{
Name=name;
Index=expression;
}
public Expression Index {get;set;}
public string Name {get;set;}
public override NodeType Type {get{return NodeType.GetArrayValue;}}
}
public class ConstString : Expression
{
public override string ToString()
{
return $"Const String: {Text}";
}
public ConstString(string tokenText)
{
Text = tokenText;
}
public string Text {get;set;}
public override NodeType Type {get{return NodeType.ConstString;}}
}
public class ConstChar : Expression
{
public override string ToString()
{
return $"Const Char: {Text}";
}
public string Text {get;set;}
public override NodeType Type {get{return NodeType.ConstChar;}}
public ConstChar(string tokenText)
{
Text = tokenText;
}
}
public class FunctionCallNode : Expression
{
public override string ToString()
{
StringBuilder b=new StringBuilder();
int i=0;
foreach(var args in Arguments)
{
b.Append($"args[{i}]: {args}\n");
i++;
}
return $"Function Call: {Name}\n{TabOver(b.ToString())}";
}
public string Name {get;set;}
public List<Expression> Arguments {get;set;}
public override NodeType Type {get{return NodeType.CallMethod;}}
public FunctionCallNode(string tokenText, List<Expression> args)
{
Name = tokenText;
Arguments = args;
}
}
public class ConstFloat : Expression
{
public override string ToString()
{
return $"Const Float: {Text}";
}
public override NodeType Type {get{return NodeType.ConstFloat;}}
public string Text {get;set;}
public ConstFloat(string tokenText)
{
Text = tokenText;
}
}
public class ConstInt : Expression
{
public override string ToString()
{
return $"Const Int: {Text}";
}
public string Text {get;set;}
public ConstInt(string tokenText)
{
Text = tokenText;
}
public override NodeType Type {get{return NodeType.ConstInt;}}
}
public class ProgramNode : Node
{
public override NodeType Type {get {return NodeType.Program;}}
public ProgramNode()
{
Functions=new List<FunctionNode>();
Variables=new List<VariableDeclarationNode>();
}
public List<FunctionNode> Functions {get;set;}
public List<VariableDeclarationNode> Variables {get;set;}
public override string ToString()
{
StringBuilder funcs=new StringBuilder();
foreach(var args in Functions)
{
funcs.Append($"{args}\n");
}
StringBuilder vars = new StringBuilder();
foreach(var args in Variables)
{
vars.Append($"{args}\n");
}
return $"Program:\nFunctions:\n{TabOver(funcs.ToString())}\nGlobal Variables:\n{TabOver(vars.ToString())}";
}
}
public class VariableDeclarationNode : Node
{
public string Name {get;set;}="";
public string VariableType {get;set;}="";
public Expression InitialValue {get;set;}=new UninitNode();
public override NodeType Type {get{return NodeType.VariableCreate;}}
public override string ToString()
{
return $"Variable declared with name: {Name}\nType: {VariableType}\nInitial Value:\n{TabOver(InitialValue.ToString())}";
}
}
public class ArgumentNode : Node
{
public override NodeType Type {get {return NodeType.Arguments;}}
public string ArgType {get;set;}="";
public string Name {get;set;}="";
public override string ToString()
{
return $"ArgType: {ArgType}\nName: {Name}";
}
}
public class ScopeNode : Node
{
public List<Node> Nodes {get;set;}=new List<Node>();
public override NodeType Type {get{return NodeType.Scope;}}
public override string ToString()
{
StringBuilder b=new StringBuilder();
foreach(var node in Nodes)
{
b.Append(node.ToString()+"\n");
}
return $"Scope:\n{TabOver(b.ToString())}";
}
}
public class FunctionNode : Node
{
public override string ToString()
{
StringBuilder b=new StringBuilder();
int i=0;
foreach(var args in Arguments)
{
b.Append($"args[{i}]: {args}\n");
i++;
}
return $"Function: {Name}\nReturn Type: {ReturnType}\nArguments:\n{TabOver(b.ToString())}\nBody:{TabOver(Body.ToString())}";
}
public string ReturnType {get;set;}="";
public override NodeType Type {get {return NodeType.Function;}}
public string Name {get;set;}="";
public Node Body {get;set;}
public List<ArgumentNode> Arguments {get;set;}=new List<ArgumentNode>();
}
public enum NodeType
{
ConstInt=0,
ConstFloat=1,
ConstString=2,
ConstChar=3,
VariableCreate=4,
GetVariableValue=5,
SetVariableValue=6,
CallMethod=7,
Return=8,
Function=9,
Program=10,
Arguments=11,
Uninit=12,
GetArrayValue=13,
Scope=14,
If=15,
Else=16,
While=17,
Break=18,
}
public abstract class Expression : Node
{
public override string ToString()
{
return $"Expression {base.ToString()}";
}
}
public class UninitNode : Expression
{
public override string ToString()
{
return $"Uninitilized {base.ToString()}";
}
public override NodeType Type {get {return NodeType.Uninit;}}
}
public abstract class Node
{
public override string ToString()
{
return $"Node:\nFilePosition: {FilePosition}\nColumn: {Column}\nLine: {Line}";
}
protected string TabOver(string text)
{
StringBuilder b=new StringBuilder();
foreach(var txt in text.Split('\n'))
{
b.Append($"\t{txt}\n");
}
return b.ToString();
}
public abstract NodeType Type {get;}
public int FilePosition {get;set;}
public int Column {get;set;}
public int Line {get;set;}
}
}