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