Here is a Lexer for a programming language I am working on. Any feedback would be appreciated. I only started learning C# a couple of days ago, so please excuse my newbie code :)
namespace Sen
{
enum TokenType
{
IDENTIFIER,
NUMBER,
STRING,
SEMICOLON,
PLUS,
MINUS,
STAR,
SLASH,
}
class Token
{
public TokenType type;
public string value;
public Token(TokenType type, string value = "")
{
this.type = type;
this.value = value;
}
}
class Lexer
{
public readonly List<Token> tokens;
private int charIdx;
private readonly string sourceRaw;
char CurrentChar
{
get { return sourceRaw[charIdx]; }
}
public Lexer(string sourceRaw)
{
this.sourceRaw = sourceRaw;
tokens = new List<Token>();
}
bool IsEnd
{
get { return charIdx >= sourceRaw.Length; }
}
char? NextChar()
{
try {
return sourceRaw[charIdx++];
} catch (IndexOutOfRangeException) {
return null;
}
}
public void Lex()
{
while (!IsEnd) {
switch (CurrentChar) {
case ';': AddToken(TokenType.SEMICOLON); break;
case ' ': break;
case '\'':
case '"':
LexString();
break;
case '+': AddToken(TokenType.PLUS); break;
case '-': AddToken(TokenType.MINUS); break;
case '*': AddToken(TokenType.STAR); break;
case '/': AddToken(TokenType.SLASH); break;
default:
if (char.IsLetter(CurrentChar)) {
LexIdentifier();
continue;
} else if (char.IsNumber(CurrentChar)) {
LexNumber();
continue;
}
throw new UnexpectedCharacterException(CurrentChar);
}
NextChar();
}
}
void AddToken(TokenType type, string value = "")
{
tokens.Add(new Token(type, value));
}
void LexIdentifier()
{
int startIdx = charIdx;
int endIdx = startIdx;
while (!IsEnd && CurrentChar != ' ' && CurrentChar != ';') {
if (!char.IsLetterOrDigit(CurrentChar) && CurrentChar != '_')
throw new UnexpectedCharacterException(CurrentChar);
NextChar();
endIdx++;
}
string value = sourceRaw[startIdx..endIdx];
AddToken(TokenType.IDENTIFIER, value);
}
void LexNumber()
{
int startIdx = charIdx;
int endIdx = startIdx;
while (!IsEnd && CurrentChar != ' ' && CurrentChar != ';' && char.IsNumber(CurrentChar)) {
NextChar();
endIdx++;
}
string value = sourceRaw[startIdx..endIdx];
AddToken(TokenType.NUMBER, value);
}
void LexString()
{
char opening = CurrentChar;
int startIdx = charIdx + 1;
int endIdx = startIdx - 1;
NextChar();
while (CurrentChar != opening) {
if (IsEnd)
throw new ExpectedCharacterException(opening);
NextChar();
endIdx++;
}
string value = sourceRaw[startIdx..endIdx];
AddToken(TokenType.STRING, value);
}
}
}