Initial Commit
This commit is contained in:
commit
af59ea75ca
|
@ -0,0 +1,133 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
*.azurePubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
packages/
|
||||
## TODO: If the tool you use requires repositories.config, also uncomment the next line
|
||||
!packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
![Ss]tyle[Cc]op.targets
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
# =========================
|
||||
# Windows detritus
|
||||
# =========================
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac desktop service store files
|
||||
.DS_Store
|
||||
|
||||
_NCrunch*
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"name": ".NET Core Launch (console)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/bin/Debug/net6.0/dumbcompiler.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/dumbcompiler.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/dumbcompiler.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/dumbcompiler.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,756 @@
|
|||
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;}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
namespace TLang
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
namespace TLang
|
||||
{
|
||||
public enum LexSymbol
|
||||
{
|
||||
Identifier = 0,
|
||||
String=1,
|
||||
Char=2,
|
||||
Integer=3,
|
||||
Float=4,
|
||||
Boolean=5,
|
||||
Symbol=6,
|
||||
|
||||
Keyword=7,
|
||||
Error=8
|
||||
}
|
||||
public class LexToken
|
||||
{
|
||||
public static string Symbols="{};(),[]=";
|
||||
public static string[] Keywords=new string[]{"func","funcptr","string","int","uint","long","ulong","short","ushort","byte","sbyte","return","if","else","while","break"};
|
||||
public LexToken(string text,int offsetInFile,int lineNumber,int columnNumber)
|
||||
{
|
||||
Func<bool> has_any_non_number=()=>
|
||||
{
|
||||
if(TokenText.Length <= 0)
|
||||
return false;
|
||||
bool hasDot=false;
|
||||
foreach(var c in TokenText)
|
||||
{
|
||||
if(c == '.')
|
||||
{
|
||||
if(hasDot) return true;
|
||||
hasDot=true;
|
||||
}
|
||||
if(c < '0' && c > '9')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
};
|
||||
TokenText=text;
|
||||
OffsetInFile=offsetInFile;
|
||||
LineNumber = lineNumber;
|
||||
ColumnNumber = columnNumber;
|
||||
string _lower=TokenText.ToLower();
|
||||
if(TokenText.Length == 0){Type=LexSymbol.Error;return;}
|
||||
if(_lower == "true" || _lower=="false")
|
||||
{
|
||||
Type = LexSymbol.Boolean;
|
||||
}
|
||||
else if(TokenText[0] == '_' || (TokenText[0] >= 'a' && TokenText[0] <= 'z') || (TokenText[0] >= 'A' && TokenText[0] <= 'Z'))
|
||||
{
|
||||
Type= Keywords.Contains(TokenText) ? LexSymbol.Keyword : LexSymbol.Identifier;
|
||||
}else if(Symbols.Contains(TokenText[0]))
|
||||
{
|
||||
Type = LexSymbol.Symbol;
|
||||
}else if(!has_any_non_number())
|
||||
{
|
||||
Type = TokenText.Contains('.') ? LexSymbol.Float : LexSymbol.Integer;
|
||||
}else{
|
||||
Type = LexSymbol.Error;
|
||||
}
|
||||
}
|
||||
public string TokenText {get;set;}
|
||||
public int OffsetInFile {get;set;}
|
||||
|
||||
public int LineNumber {get;set;}
|
||||
public int ColumnNumber {get;set;}
|
||||
|
||||
public LexSymbol Type {get;set;}
|
||||
}
|
||||
public class Lexer
|
||||
{
|
||||
public static IEnumerable<LexToken> GetTokens(TextReader reader)
|
||||
{
|
||||
|
||||
LexToken value = new LexToken("",0,0,0);
|
||||
|
||||
int read=0;
|
||||
int i=0;
|
||||
int col=0;
|
||||
int ln=0;
|
||||
StringBuilder b=new StringBuilder();
|
||||
|
||||
Func<bool> pop_off = ()=>{
|
||||
//we need to pop off what ever is in array
|
||||
if(b.Length <= 0)
|
||||
return false;
|
||||
value=new LexToken(b.ToString(),i,ln,col);
|
||||
b.Clear();
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
|
||||
while((read=reader.Read()) != -1)
|
||||
{
|
||||
|
||||
//neq(T,T)
|
||||
//lte(T,T)
|
||||
//gte(T,T)
|
||||
//gt(T,T)
|
||||
//lt(T,T)
|
||||
//eq(T,T)
|
||||
//add(T,T)
|
||||
//concat(T,T)
|
||||
//tostr(T)
|
||||
//toint(T)
|
||||
//touint(T)
|
||||
//tolong(T)
|
||||
//toulong(T)
|
||||
//toshort(T)
|
||||
//toushort(T)
|
||||
//tobool(T)
|
||||
//tobyte(T)
|
||||
//tosbyte(T)
|
||||
//hasvalue(T)
|
||||
//sub(T,T)
|
||||
//times(T,T)
|
||||
//div(T,T)
|
||||
//mod(T,T)
|
||||
//split(s,symbol,expected_num)
|
||||
//split(s,symbol)
|
||||
//trimend(s,sym)
|
||||
//trimstart(s,sym)
|
||||
//len(T[])
|
||||
//add(T[],T)
|
||||
//remove(T[],T)
|
||||
//removeat(T[],i)
|
||||
//insert(T[],T,i)
|
||||
//create_stream(read_ptr,write_ptr,seek_ptr,close_ptr)
|
||||
//read_stream(stream,byte[],int)
|
||||
//write_stream(stream byte[],int)
|
||||
|
||||
switch(read)
|
||||
{
|
||||
case '{':
|
||||
case '}':
|
||||
case '(':
|
||||
case ')':
|
||||
case ',':
|
||||
case '[':
|
||||
case ']':
|
||||
case '=':
|
||||
case ';':
|
||||
col++;
|
||||
i++;
|
||||
if(pop_off())
|
||||
yield return value;
|
||||
b.Append((char)read);
|
||||
if(pop_off())
|
||||
yield return value;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '.':
|
||||
b.Append((char)read);
|
||||
col++;
|
||||
i++;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
|
||||
if(read == ' ') {i++;col++;}
|
||||
if(read == '\t') {i++;col+=4;}
|
||||
|
||||
if(pop_off())
|
||||
yield return value;
|
||||
break;
|
||||
default:
|
||||
//needs to start with _ or letter
|
||||
//can contain numbers
|
||||
col++;
|
||||
if(read == '\n') {col=0;ln++;}
|
||||
|
||||
i++;
|
||||
if(read == '_' || (read >= 'a' && read <= 'z') || (read >= 'A' && read <= 'Z'))
|
||||
{
|
||||
b.Append((char)read);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}if(pop_off())
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using TLang;
|
||||
//string code = "func main(string[] args) { int i = times(4,8); print(i);}";
|
||||
string code = "func main(string[] args) { int i = 0; int j = 42; int k=demi(1,1); while { int f=0; } int j=0; } int j=42; func sub(int i){int j=0;}";
|
||||
|
||||
var parsed=Parser.Parse(Lexer.GetTokens(new StringReader(code)).ToList());
|
||||
Console.WriteLine(parsed);
|
|
@ -0,0 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in New Issue