267 lines
8.2 KiB
C#
267 lines
8.2 KiB
C#
|
using System.Globalization;
|
||
|
using System.Text;
|
||
|
|
||
|
namespace langtest
|
||
|
{
|
||
|
public enum LexTokenType
|
||
|
{
|
||
|
PLUS=0,
|
||
|
MINUS=1,
|
||
|
MULTIPLY=2,
|
||
|
DIVIDE=3,
|
||
|
MOD=4,
|
||
|
LPAREN=5,
|
||
|
RPAREN=6,
|
||
|
IDENTIFER=7,
|
||
|
NUMBER=8,
|
||
|
EQUALS=9,
|
||
|
COMMA=10,
|
||
|
ERROR=11,
|
||
|
SEMI=12,
|
||
|
LBRACE=13,
|
||
|
RBRACE=14,
|
||
|
STRING=15,
|
||
|
}
|
||
|
|
||
|
public class LexToken
|
||
|
{
|
||
|
public LexToken()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
public LexToken(string text)
|
||
|
{
|
||
|
Text = text;
|
||
|
Type=char.IsLetter(text.FirstOrDefault()) ? LexTokenType.IDENTIFER : (char.IsNumber(text.FirstOrDefault()) ? LexTokenType.NUMBER : LexTokenType.ERROR);
|
||
|
}
|
||
|
|
||
|
public LexTokenType Type {get;set;}
|
||
|
public string Text {get;set;}="";
|
||
|
}
|
||
|
|
||
|
public static class Lexer
|
||
|
{
|
||
|
public static string? Prompt(string t)
|
||
|
{
|
||
|
Console.Write(t);
|
||
|
return Console.ReadLine();
|
||
|
}
|
||
|
public static IEnumerable<LexToken> EnumerateTokens(string text)
|
||
|
{
|
||
|
int filePos=0;
|
||
|
Func<(char chr,bool esc)> read_char = ()=>{
|
||
|
int txt=text[filePos++];
|
||
|
|
||
|
if(txt == '\\')
|
||
|
{
|
||
|
|
||
|
//we are to escape
|
||
|
txt = text[filePos++];
|
||
|
if(txt == 'x')
|
||
|
{
|
||
|
|
||
|
char[] chars=new char[4];
|
||
|
|
||
|
|
||
|
for(int i = 0 ;i<4;i++)
|
||
|
{
|
||
|
txt = text[filePos++];
|
||
|
|
||
|
chars[i] = (char)txt;
|
||
|
}
|
||
|
return ((char)Int16.Parse(new string(chars), NumberStyles.AllowHexSpecifier),true);
|
||
|
|
||
|
}else{
|
||
|
|
||
|
if(txt == 'n')
|
||
|
{
|
||
|
return ('\n',true);
|
||
|
}
|
||
|
if(txt == 'r')
|
||
|
{
|
||
|
return ('\r',true);
|
||
|
}
|
||
|
if(txt == 't')
|
||
|
{
|
||
|
return ('\t',true);
|
||
|
}
|
||
|
return ((char)txt,true);
|
||
|
}
|
||
|
}
|
||
|
else{
|
||
|
return ((char)txt,false);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Func<string> read_string = ()=>{
|
||
|
StringBuilder b=new StringBuilder();
|
||
|
while(true)
|
||
|
{
|
||
|
(char chr,bool esc) txt=read_char();
|
||
|
if(txt.chr == '\"' && !txt.esc)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
b.Append(txt.chr);
|
||
|
}
|
||
|
return b.ToString();
|
||
|
};
|
||
|
|
||
|
StringBuilder b=new StringBuilder();
|
||
|
while(filePos < text.Length)
|
||
|
{
|
||
|
char c=text[filePos++];
|
||
|
|
||
|
if(c == '\"')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
string str = read_string();
|
||
|
yield return new LexToken(){Text = str,Type = LexTokenType.STRING};
|
||
|
}
|
||
|
else
|
||
|
if(c == '\'')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
char str = read_char().chr;
|
||
|
filePos++;
|
||
|
yield return new LexToken(){Text = ((int)str).ToString(),Type = LexTokenType.NUMBER};
|
||
|
}else
|
||
|
if(c == '+')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="+",Type = LexTokenType.PLUS};
|
||
|
}else
|
||
|
if(c == '-')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="-",Type = LexTokenType.MINUS};
|
||
|
}else
|
||
|
if(c == '*')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="*",Type = LexTokenType.MULTIPLY};
|
||
|
}else
|
||
|
if(c == '/')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="/",Type = LexTokenType.DIVIDE};
|
||
|
}else
|
||
|
if(c == '%')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="%",Type = LexTokenType.MOD};
|
||
|
}else if(c == '{')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="{",Type = LexTokenType.LBRACE};
|
||
|
}else if(c == '}')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="}",Type = LexTokenType.RBRACE};
|
||
|
}
|
||
|
else
|
||
|
if(c == '(')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="(",Type = LexTokenType.LPAREN};
|
||
|
}else
|
||
|
if(c == ')')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text=")",Type = LexTokenType.RPAREN};
|
||
|
}else if(c == '=')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text="=",Type = LexTokenType.EQUALS};
|
||
|
}
|
||
|
else if(c == ',')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text=",",Type = LexTokenType.COMMA};
|
||
|
}
|
||
|
else if(c == ';')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
yield return new LexToken(){Text=";",Type = LexTokenType.SEMI};
|
||
|
}
|
||
|
else if(c == '\n' || c == ' ' || c == '\t')
|
||
|
{
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
|
||
|
|
||
|
}else{
|
||
|
b.Append(c);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
if(b.Length > 0)
|
||
|
{
|
||
|
yield return new LexToken(b.ToString());
|
||
|
b.Clear();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|