commit af59ea75caa090b3f5f7edddabaf290dafa2c0dd Author: Michael Nolan Date: Wed Sep 7 11:10:42 2022 -0500 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b956f9 --- /dev/null +++ b/.gitignore @@ -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* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..392fc1c --- /dev/null +++ b/.vscode/launch.json @@ -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" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..5378510 --- /dev/null +++ b/.vscode/tasks.json @@ -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" + } + ] +} \ No newline at end of file diff --git a/AST.cs b/AST.cs new file mode 100644 index 0000000..cc97982 --- /dev/null +++ b/AST.cs @@ -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 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 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) + { + i++; + List argumentNodes = new List(); + //type arg,type arg + for(;i 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,FunctionNode node) + { + node.Body=ParseStatement(ref i,tokens); + } + + private static Expression ParseExpression(ref int i, List 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 args=new List(); + Console.WriteLine(tokens[i].TokenText); + + i+=2; + for(;i Arguments {get;set;} + public override NodeType Type {get{return NodeType.CallMethod;}} + public FunctionCallNode(string tokenText, List 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(); + Variables=new List(); + } + public List Functions {get;set;} + + public List 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 Nodes {get;set;}=new List(); + 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 Arguments {get;set;}=new List(); + } + 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;} + } + + +} \ No newline at end of file diff --git a/FunctionCallNode.cs b/FunctionCallNode.cs new file mode 100644 index 0000000..f514a72 --- /dev/null +++ b/FunctionCallNode.cs @@ -0,0 +1,4 @@ +namespace TLang +{ + +} \ No newline at end of file diff --git a/Lexer.cs b/Lexer.cs new file mode 100644 index 0000000..2bc8b13 --- /dev/null +++ b/Lexer.cs @@ -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 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 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 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; + } +} +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..f0e94c1 --- /dev/null +++ b/Program.cs @@ -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); \ No newline at end of file diff --git a/dumbcompiler.csproj b/dumbcompiler.csproj new file mode 100644 index 0000000..40c60dd --- /dev/null +++ b/dumbcompiler.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + +