用C#为基本解释器编写标记器类
为了好玩,我正在尝试用C#编写一个基本的解释器。下面是我的标记器类(只有几个关键字)。我在寻找任何建议或意见。。。对我来说,代码清晰比效率更重要。非常感谢用C#为基本解释器编写标记器类,c#,C#,为了好玩,我正在尝试用C#编写一个基本的解释器。下面是我的标记器类(只有几个关键字)。我在寻找任何建议或意见。。。对我来说,代码清晰比效率更重要。非常感谢 class Tokenizer { const string Operators = "+-/*%<>=&|"; private List<string> Keywords = new List<string>{"LET", "DIM", "PRINT",
class Tokenizer
{
const string Operators = "+-/*%<>=&|";
private List<string> Keywords = new List<string>{"LET", "DIM", "PRINT", "REM"};
private List<string> tokens = new List<string>();
private List<string> tokenTypes = new List<string>();
private int tokenIndex;
// Turn command string into tokens
public void Tokenize(string cmdLine)
{
string token = "";
char lastc = ' ';
bool inString = false;
tokens.Clear();
tokenTypes.Clear();
// Step through line and split into tokens
foreach (char c in cmdLine)
{
if (c == '"') inString = !inString;
if (!inString)
{
if (IsOperator(lastc)) AddToken(ref token);
if (IsWhitespace(c)) AddToken(ref token);
if (IsOperator(c)) AddToken(ref token);
if (IsNumber(c) && !IsNumber(lastc)) AddToken(ref token);
if (!IsWhitespace(c)) token += c;
}
else
token += c;
lastc = c;
}
// Add last token
AddToken(ref token);
tokenIndex = 0;
}
public string Token()
{
return tokens[tokenIndex];
}
public string TokenType()
{
return tokenTypes[tokenIndex];
}
public void NextToken()
{
tokenIndex++;
}
public bool TokensLeft()
{
return tokenIndex < tokens.Count;
}
// Add a token to the collection
private void AddToken(ref string token)
{
if (token.Trim() != "")
{
// Determine token type
string tokenType = "Identifier";
if (IsOperator(token[0])) tokenType = "Operator";
if (IsNumber(token[0])) tokenType = "Number";
if (token[0] == '"') tokenType = "String";
if (Keywords.Contains(token.ToUpper())) tokenType = "Keyword";
tokens.Add(token);
tokenTypes.Add(tokenType);
token = "";
}
}
private bool IsWhitespace(char c)
{
return (c.ToString() != c.ToString().Trim());
}
private bool IsOperator(char c)
{
return Operators.Contains(c);
}
private bool IsNumber(char c)
{
return Char.IsNumber(c);
}
}
类标记器
{
常量字符串运算符=“+-/*%=&|”;
私有列表关键字=新列表{“LET”、“DIM”、“PRINT”、“REM”};
私有列表令牌=新列表();
私有列表标记类型=新列表();
私有整数索引;
//将命令字符串转换为令牌
公共void标记化(字符串cmdLine)
{
字符串标记=”;
char lastc='';
bool inString=false;
tokens.Clear();
tokenTypes.Clear();
//单步通过行并拆分为令牌
foreach(cmdLine中的字符c)
{
如果(c=='“')inString=!inString;
如果(!inString)
{
if(等运算符(lastc))AddToken(ref token);
if(IsWhitespace(c))AddToken(ref token);
if(等位符(c))AddToken(ref token);
if(IsNumber(c)&&!IsNumber(lastc))AddToken(ref token);
如果(!IsWhitespace(c))标记+=c;
}
其他的
令牌+=c;
lastc=c;
}
//添加最后一个令牌
AddToken(ref-token);
指数=0;
}
公共字符串标记()
{
返回令牌[令牌索引];
}
公共字符串标记类型()
{
返回令牌类型[tokenIndex];
}
下一步公开无效()
{
tokenIndex++;
}
公共bool TokensLeft()
{
返回tokenIndex
您通常不想手动编写这样的解析器代码,如果您要处理计算机语言的解析,而不仅仅是为了好玩/编码练习,那么学习一个好的解析器生成器工具(例如)是一项很好的时间投资。也就是说,如果您真的想手动执行此操作,您需要考虑以下事项:
- 使用StringBuilder而不是字符串
- 仅仅检查引号是不够的,那么转义引号呢
- 您将如何处理浮点数(所有格式)
- 您将如何处理包含数字的标识符
这些是您将遇到的一些问题,我再次建议您学习解析器生成器工具,它使这类事情更加有趣(更不用说正确和高效)。我不同意。十多年来,我一直在专业编写编译器,从未使用过解析器生成器工具。当然,它们非常适合快速创建简单语言的解析器。但对于需要复杂的错误报告、错误恢复、中间编辑程序的语义分析或深度歧义语法的语言,根据我的经验,手写的递归下降解析器是一个不错的选择。对于复杂现实世界语言的商业解析器,我完全尊重您的意见。我想我把它看作三个层次:1)语法分析器生成器工具过于简单的普通语言2)中等复杂的语言(具有中等的性能/报告要求)语法分析器生成器工具真正出色的语言3)高度复杂的语言(或严格的性能/报告要求),在需要控件的地方,只有手工编写的解析器才能提供。我仍然认为,在尝试自己编写解析器之前,学习解析器生成器工具是值得的。