用C#为基本解释器编写标记器类

用C#为基本解释器编写标记器类,c#,C#,为了好玩,我正在尝试用C#编写一个基本的解释器。下面是我的标记器类(只有几个关键字)。我在寻找任何建议或意见。。。对我来说,代码清晰比效率更重要。非常感谢 class Tokenizer { const string Operators = "+-/*%<>=&|"; private List<string> Keywords = new List<string>{"LET", "DIM", "PRINT",

为了好玩,我正在尝试用C#编写一个基本的解释器。下面是我的标记器类(只有几个关键字)。我在寻找任何建议或意见。。。对我来说,代码清晰比效率更重要。非常感谢

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)高度复杂的语言(或严格的性能/报告要求),在需要控件的地方,只有手工编写的解析器才能提供。我仍然认为,在尝试自己编写解析器之前,学习解析器生成器工具是值得的。