我的计算器——3 词法分析

 

3词法分析

 

关键词:C# .NET 计算器 词法分析 语法分析 表达式计算 ConExpress Calculator
 
承接上一篇,这一篇讲如何把表达式转换成记号对象,这里就涉及到了编译原理中的词法分析。关于编译原理我不想多讲,毕竟我自己也不怎么熟悉,现在只知道其中有个有限自动机的概念,呵呵。不管什么概念,用代码实现才是最终目标。
 
因为不清楚字符串中到底包含什么字符,只能一个个字符进行处理,采用循环一次次向后取一个字符进行判断。这里建立一个工厂类TokenFactory,由这个类负责对表达式进行分析并“制造”出TokenRecord对象。其中包括两个方法,LexicalAnalysis和ProduceToken。LexicalAnalysis用于词法分析,分析到符合规则的记号对象后调用ProduceToken方法,“制造”出对应的TokenRecord对象。这里偷了一点懒,把所有方法全部写成了static,这样就不用实例化多个子类了。
从这个类衍生出多个子类:
TokenKeywordFactory:用于处理关键字
TokenSymbolFactory:用于处理运算符
TokenStringFactory:用于处理字符串
TokenNumberFactory:用于处理数字
类图如下:

TokenFactory

 

 

分析表达式的入口只有一个,就是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.取字符“*

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值