jcSQL词法分析器对字符串token的解析

上星期写完词法分析器的时候,曾遇上一个无关紧要却X疼的问题。毕竟是第一次完整地写整个语言的编译器(暂且这么叫着吧,解释器更靠谱),由于经验不足,在字符串解析这一块驻足了两天才解决掉,这里记录下来供以后参考。哦对了,之所以想自己手写词法分析器,并不是我不知道有自动工具可以自动生成,而是我不会用,嗯,果然高冷。

词法分析器的作用简而言之就是将语言分割成一个一个独立的词法单元(单词),并赋予一定的类型。(如果不了解其作用,建议参考词法分析)

例如:

a = 3 ;

我们就可以将其分课程一个个有意义的单元,并赋予类型:

<=,NE>

<3,NUM>

<;,SEMI>

和就是分割好的单词序列。在一般情况下,一门语言的词法分析器总会遇上要分析字符串成分的情况,比如表达式

val = "xxx" 或者 val = ‘xxx‘

我并未参考其他语言是如何分析,仅凭猜测,自认为应该解析成如下形式:

<=,NE>

<‘/",SINGLEQUOTE/DOUBLEQUOTE>

当然也许这不是一个好的类型单词分配方法,但起码不会是一个错误方法吧,到现在,语法分析阶段工作的还挺好的,也许会有更好的办法,还需要多参考前辈们的。

这个时候问题就是,当遇上这样的句子时:

a = "xxxxxxx" b="ssssssss"

因为在一个SQL语句中不可能一辈子咱们就出现一个字符串单元,所以这个怎么解析当时很费了点脑筋。如果没注意,就会解析成

<=,NE>

<",DOUBLE_QUOTE>

<",DOUBLE_QUOTE>

<",DOUBLE_QUOTE>

<",DOUBLE_QUOTE>

如果不加以控制,这显然是错的,因为b=在这里显然是两个单词,而不是STRING。于是我开始寻觅各种办法解决这个问题:第一个想到的是用bool类型来控制,判断引号出现的单复数,如果是true则为复数,即收尾的符号,这样这个问题就解决了。但是,脑脑子里思考问题的解决方案永远是奔向理想目标中的其中一条道路,很多岔路是动手的时候出现的,于是真的出现问题了,参看下面伪代码,其中flag1与2分别代表单引号与双引号的判断flag。

get_next_token()
    {
        while (p != val.size())
        {
            if (flag)
            {
                std::string v=get_string();
                continue;
            }
            switch (c)
            {
            case ‘\‘‘:
                if (flag==true)//the begin quote
                {
                    flag = false;
                }
                else if (flag==false)
                {
                    flag = true;
                }
                consume();
                break;
            default:
                consume();
            }
        }
    }

switch语句内的代码逻辑是没有任何问题的,问题出在,取字符串单词的判断上:当下一个单词是字符串时,取出之后便会执行continue,这时flag 是无法被改变状态的,所以当下一次取单词进入函数时又会进入开始的if逻辑,当时我在这种解决方法上进行了很多次的修改,均告失败,问题重重,于是只得另寻方案,每当这种时候都恨自己脑瓜不够机灵,想不到优雅的办法解决这种问题,当然了也许是条件限制,导致自己没法往优雅的解决方法上想,:p,我倾向于后者。后来也试过用用计数器的方式,也是失败了,掰着掰着就醉了,好一个,众人皆醒我独醉,醉完媳妇旁撅着睡。(诶?!我不是在寝室吗?)

好在把各种烂方法使了过后,想到了一个最终解决方法,使用了一个栈,当栈里保存着有引号的时候(当前符号落到引号上时在switch内的每个case压栈,如代码所示。),说明这一轮要取的单词属于字符串,当当前字符又落到引号上时,判断栈里是否有引号,如果有,则说明是收尾引号,这时清空栈。

//由于get_token函数过长,此处仅贴上部分片段
    if (!quote_stack.empty())//string_identifier.first stores the quotes
    {
        if (quote_stack.top() == c)
        {
            consume();
            char temp = quote_stack.top();
            quote_stack.pop();
            if (temp==‘\‘‘)
            {
                return token(tag::SINGLEQUOTE, "‘");
            }
            return token(tag::DOUBLEQUOTE, "\"");
        }
        else
        {
            std::string id = STRINGS_WITH_TERMINATION(quote_stack.top()).c_str();
            token tk(tag::STRING, id.c_str());
            if (!id.empty())
            {
                return token(tk);
            }
        }
    }

    //switch内部:
        case ‘\‘‘:
            consume();
            quote_stack.push(‘\‘‘);
            return token(tag::SINGLEQUOTE, "‘");
        case ‘"‘:
            consume();
            quote_stack.push(‘"‘);
            return token(tag::DOUBLEQUOTE, "\"");

这个方法目前运行良好,由于任务的特殊性,栈内最多会容纳两个字符,由于stack内部由deque实现(C++ STL),空间上多少浪费了一点,不过这个方法将任务简化,并且也挺好理解,同时相比flag的方法,flag更容易有在其他函数中无意赋值导致全局变量污染问题的风险。当然了,您可以将其替换为一个两个字节的数组,抽象成一个类来解决,我这里暂时先不做优化。

其实这也只是一个权宜之计,我相信一定有优雅且更加高效的设计或者方法,期待可以学到。

jcSQL词法分析器对字符串token的解析

时间: 2024-10-30 14:09:48

jcSQL词法分析器对字符串token的解析的相关文章

Python-Json字符串和XML解析

Python-json字符串和xml解析 JSON:JavaScript Object Notation(JavaScript 对象表示法) JSON是存储和交换文本信息的语法,类似XML JSON比XML更小,更快,更易解析. 1.JSON语法与语法规则 JSON语法是JavaScript语法的子集. JSON语法是JavaScript对象表示语法的子集. 数据在名称/值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 1.1:JSON对象 JSON对象是保存在花括号中的.对象可以包含多个

LoadRunner11 实现token的解析与认证

问题描述: 1.当前系统通过token实现系统安全验证,登录成功后,token被存储在返回体中(reaponse body),后续服务器请求时,需要将该token添加到请求头部(request header)中: 2.当前web服务访问时,强制限制必须适应谷歌浏览器: 3.Lr录制脚本时,需要通过代理的方式录制,但录制结果回放时,总是提示错误: Error -26630: HTTP Status-Code=401 (Unauthorized) for ***: ##解决办法: 1.打开录制的脚本

php前端传过来的字符串在后台解析成数组 同时批量添加

//前端页面代码 获取多行的obj function addBedType() { var obj = document.getElementsByName('type_name'); var duoxuan = ''; for (var i = 0; i < obj.length; i++) { duoxuan += obj[i].value + ',';//如果选中,将value添加到变量duoxuan中 //alert(duoxuan);} if (duoxuan.length < 1)

C语言之字符串典型例题解析

今天又遇见几个好题,和以前的一些凑一块写一篇文章,作为我延迟去自习室的一个借口吧. 首先是第一题 1 int fun(char* s){ 2 char* t = s; 3 while(*t++); 4 return t-s; 5 } 6 fun函数的功能是_______ 7 比较两个字符串的大小 8 计算s所指字符串占用内存的大小 9 技术s所指字符串的长度 10 将s所指字符串复制到字符串t中 题目有四个选项,为什么我会选这个题呢,因为自己在面试C++的岗位中第一次遇见,印象里好像是写错了,然

ajax查询数据库,服务器传回json字符串,js解析json

服务器端获得要查询的东西,查询数据库,将查询的信息,以json字符串的形式返回给浏览器 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String departmentID=request.getParameter("departmentID"); DataBaseHandle dataBaseHandl

Memcached中对象反序列化和json字符串用jackson解析成对象的比较

如果项目已经发布,如果临时想对某个在Memcached中的key修改值,那么以对象形式存储的话,将很难修改,但如果以字符串形式存储,通过json解析成对象的话,则会方便很多,因为通过界面往Memcached 添加字符串值是很简单的. 现在来比较一下这两种方式在时间消耗方面的差异: package bean; import java.io.Serializable; public class User implements Serializable{ /** * 序列号 */ private st

Python之字符串小代码解析

本篇只是拿一段代码来对python中的字符串的一些使用做解释,来让大家更加了解python Python 3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:25:23) [MSC v.1600 64 bit (AMD64)] on win32 Type "copyright", "credits" or "license()" for more information. >>> pystr=

php 中文字符串截取方法解析

用PHP函数substr截取中文字符可能会出现乱码,主要是substr可能硬生生的将一个中文字符“锯”成两半.解决办法: 1.使用mbstring扩展库的mb_substr截取就不会出现乱码了. 2.自己书写截取函数,但效率不如用mbstring扩展库来得高. 3.如果仅是为了输出截取的串,可用如下方式实现:substr($str, 0, 30).chr(0). substr()函数可以分割文字,但要分割的文字如果包括中文字符往往会遇到问题,这时可以用mb_substr()/mb_strcut这

后台给前台传JSON字符串,前台解析并拼接显示

后台传JSON 1 public class CourseType : IHttpHandler 2 { 3 Epoint.PeiXun.Bizlogic.BLL.CourseLibrary.PX_CourseType.B_PX_CourseType b_coursetype = new Epoint.PeiXun.Bizlogic.BLL.CourseLibrary.PX_CourseType.B_PX_CourseType(); 4 5 List<CourseTypeData> list_