3词法分析
关键词:C# .NET 计算器 词法分析 语法分析 表达式计算 ConExpress Calculator
承接上一篇,这一篇讲如何把表达式转换成记号对象,这里就涉及到了编译原理中的词法分析。关于编译原理我不想多讲,毕竟我自己也不怎么熟悉,现在只知道其中有个有限自动机的概念,呵呵。不管什么概念,用代码实现才是最终目标。
因为不清楚字符串中到底包含什么字符,只能一个个字符进行处理,采用循环一次次向后取一个字符进行判断。这里建立一个工厂类TokenFactory,由这个类负责对表达式进行分析并“制造”出TokenRecord对象。其中包括两个方法,LexicalAnalysis和ProduceToken。LexicalAnalysis用于词法分析,分析到符合规则的记号对象后调用ProduceToken方法,“制造”出对应的TokenRecord对象。这里偷了一点懒,把所有方法全部写成了static,这样就不用实例化多个子类了。
从这个类衍生出多个子类:
TokenKeywordFactory:用于处理关键字
TokenSymbolFactory:用于处理运算符
TokenStringFactory:用于处理字符串
TokenNumberFactory:用于处理数字
类图如下:
分析表达式的入口只有一个,就是TokenFactory中的LexicalAnalysis。TokenFactory类的代码如下:
internal class TokenFactory
{
/// <summary>
/// 生成记号
/// </summary>
/// <param name="TokenWord">记号对应的字符串</param>
/// <param name="Index">记号开始的列序号</param>
/// <returns>记号对象</returns>
public static TokenRecord ProduceToken(string TokenWord, int Index)
{
throw new Exception("必须在子类中实现方法");
}
/// <summary>
/// 词法分析
/// </summary>
/// <param name="TokenList">记号对象列表</param>
/// <param name="Code">表达式</param>
/// <param name="Index">列序号</param>
public static void LexicalAnalysis(List<TokenRecord> TokenList, string Code, ref int Index)
{
string strTempChar = string.Empty;//临时字符
for (int intIndex = 0; intIndex < Code.Length; intIndex++)
{
strTempChar = Code.Substring(intIndex, 1);//获取当前字符
//关键字分析
if ((strTempChar.CompareTo("A") >= 0 && strTempChar.CompareTo("Z") <= 0)
|| (strTempChar.CompareTo("a") >= 0 && strTempChar.CompareTo("z") <= 0))//如果当前字符为字母,进行关键字处理
{
TokenKeywordFactory.LexicalAnalysis(TokenList, Code, ref intIndex);
}
else if (strTempChar.Equals("'") || strTempChar.Equals("/""))//如果是字符串标识符,进行字符串处理
{
TokenStringFactory.LexicalAnalysis(TokenList, Code, ref intIndex);
}
else if (strTempChar.CompareTo("0") >= 0 && strTempChar.CompareTo("9") <= 0)//数值处理
{
TokenNumberFactory.LexicalAnalysis(TokenList, Code, ref intIndex);
}
else if (TokenSymbolFactory.GetOperateList().Contains(strTempChar))//运算符处理
{
//有些运算符为双字符,但这里所有的双字符运算符的前一个字符都有对应的单字符运算符,可以只考虑一个字符
TokenSymbolFactory.LexicalAnalysis(TokenList, Code, ref intIndex);
}
else if (strTempChar.Equals(" "))
{
//如果是空格,则忽略不处理
}
else//错误处理
{
//抛出错误
throw new Exception(string.Format("语法错误,列{0},包含不合法字符:{1}。", intIndex.ToString(), strTempChar));
}
}//for
}//LexicalAnalysis
}//class
这里的LexicalAnalysis方法中,只需要判断当前字符是否符合一定的起始规则,如果符合起始规则,就交给对应的工厂类去处理。
还是用例子来讲吧,比如123.3*2-(24+34),分析成记号对象就是
记号对象 | 对应表达式 |
TokenValue | 123.3 |
TokenMultiply |
* |
TokenValue | 2 |
TokenMinus | - |
TokenLeftBracket | ( |
TokenValue | 24 |
TokenPlus | + |
TokenValue | 34 |
TokenRightBracket | ) |
这里的处理过程是
1.取字符“1”,转到TokenNumberFactory,把分析取到的字符串“123.3”转换为TokenNumber并存到TokenList中
2.取字符“*