Lex中有趣问题

Lex和Yacc是Unix下不错的词法分析器和语法分析器,在linux下,这两个工具被成为flex和bison,也是C++经常用来构建字符分析程序的工具。

本文不是一篇入门文章,我们假设您已经了解了Lex和Yacc的基本语法

入门文章请参考IBM的:【Yacc 与 Lex 快速入门】

我们这里讨论一些其有趣的用法和注意的事项

字符串的识别

常规的正则式和匹配问题都难不倒大家,那么下面来想一个问题,C语言中字符串如何识别?

我们知道,字符串一般是这样的

"some \"string\" problem.\n"

但我们会发现其中包含有转移符和引号,如何只是简单的如下书写正则式:

\"[^"]*\"

则会导致引号表达能力不全,不能满足C语言的要求。

所以我们考虑将里面的表达部分拆开,首先,虽然不能有引号,但可以让其有\",所以我们的正则式改完如下:

\"(\\"|[^"])*\"

好的,那么我们可以用这个\"转义引号了,但如何你认为就这样就可以了,那未免有点心急,因为还有很重要的情况,那就是后一半中其实也可以含有\,但其实我们的\实际上是转义符,要成对配套使用,单独用\是不正确的,所以我们应该加上对其的限制,不让\随意出现,那么我们的正则变成了这样:

\"(\\.|[^"\\])*\"

好,这就是我们的C语言字符串识别的正则式了。

注释的识别

恩,解决了棘手的字符串识别难题,那么,又发现了另外的情况,C语言有两种注释,如何正确的识别他们呢?

// hello world

/**
 * hello world
 */

首先第一种较为容易实现,类似上面的方法,只要让注释中不存在换行符就好:

//[^\n]*

但下面一种较为复杂,当然也有简单实现的方式

"/*"([^\*]|(\*)*[^\*/])*(\*)*"*/" 

这个正则式十分复杂,我们分解讲解一下

"/*"   ( [^\*]  |  (\*)*  [^\*/] )*  (\*)*   "*/"

( [^\*] | (\*)* [^\*/] )*这一段是在找所以的非*内容,或者是*后面不是*/的部分,这是被允许的,有人问,为何里面*不能跟*呢?

这是由于一旦可以跟*,下一次匹配就限制不住匹配/开头的了,为了避免这一情况,做出限制,但又由于可能存在末尾连续的*的情况,所以在后面又补充了连续的*

这里,其实使用别的正则引擎,还有简单的解决方案,具体可以参考这篇英文博客:【Finding Comments in Source Code Using Regular Expressions】

另外在Lex的实际使用中,还有一种简便的方式,那就是利用固定的C代码,处理注释的丢弃,方法如下:

"/*"                    comment();

%%

comment()
{
    char c, c1;

loop:
    while ((c = input()) != ‘*‘ && c != 0)
        putchar(c);

    if ((c1 = input()) != ‘/‘ && c != 0)
    {
        unput(c1);
        goto loop;
    }

    if (c != 0)
        putchar(c1);
}
时间: 2024-10-06 23:58:41

Lex中有趣问题的相关文章

C 语言中有趣第指针操作(转)

http://blog.csdn.net/ghevinn/article/details/37651149(反汇编题目需要分析) 4.取出内存区域的值 在取某内存地址开始的一个区域的值的时候,取出的值取决于用来取值的类型,譬如int为4个byte,char为1个byte,程序如: void main(){ int a[2] = {261,0}; int *pi = a; char *p = (char*)pi; cout << *(int *)p++ << endl;  //取出p

python中有趣的函数

filter(function, sequence):对sequence中的item依次执行function(item),将执行结果为True的item组成一个List/String/Tuple(取决于sequence的类型)返回: >>> def f(x): return x % 2 != 0 and x % 3 != 0 >>> filter(f, range(2, 25)) [5, 7, 11, 13, 17, 19, 23] >>> def f

一些JAVA中有趣的面试题

这几天的JAVA培训课上,不断的唤醒自己对JAVA的理解(时间太长,大学学的快忘干净了),其中有一些很有趣的面试题,都是在抠JAVA细节(唉,我是那种见坑就往下跳的人,一做就错),下面就来分享一下: 1)用JAVA程序写出当你在超市购物花费1.1元时,你给收银员2元钱,收银员找你0.9元的过程: 当时一看题目,好简单啊!迅速写出: public class Sell{ public static void main(String[] args){ double total = 2.0; doub

小程序开发中有趣的事情

小程序开发做了半年了,断断续续地利用课余时间写了一大部分. 期间遇到了很多坑和技巧,个人感觉十分有趣. 1.textarea 小程序里面的textarea是我遇到的第一个坑. textarea 在小程序里面看起来似乎和HTML里的一样,但是页面一滑动就有问题:欸欸欸??卧槽,卧槽,他怎么不动?:如果页面有弹层,弹层弹出的瞬间,卧槽卧槽?这个怎么在最上面?.textarea在小程序里面是原生层级最高的组件,z-index对他没用,并且在swipe.scroll-view.canve里面会出现奇奇怪

方法重载中有趣的问题

看到一个比較有意思的问题 public class InvokeTest { public static void main(String[] args) { invoke(null); } // method_1 public static void invoke(Object obj) { System.out.println("Object obj"); } // method_2 public static void invoke(int[] arr) { System.out

画风清奇!盘点各编程语言中有趣的开源项目!

生活不易,编程苦闷,不如“人为制造”点趣味,让日子过得更加有玩味感. 本文参考了一些项目推荐,整理了一些编程语言中个人认为比较有意思,也相对实用的开源项目,每个语言列的都不多,感兴趣的有空可以试试看. 一.Go 1.Gobot Gobot 是一个机器人.无人机和物联网框架,提供在同一时间合并多个不同设备的简单且强大的解决方案. Gobot 目前共支持18个不同的平台,它包含一个 cppp.io 兼容的 RESTful API 来查询在群中运行的任何连接.设备或机器人的状态,还能够直接向设备和机器

webMethods中有趣的尝试【一】

webMethods的flowService是一种典型的工作流模式编程,因此有一些使用会和代码不一样.出于这样的原因,本人对flowService的活用做了一些测试. 一.递归 在flowService中调用自身. 测试结果:可以实现递归功能,同编码一样.需要指定跳出条件,不然会有死循环的编译错误. 二. exit exit功能有三种用法跳出循环(相当于java中的break),跳出flow(相当于exit()),跳到父节点(相当于continue). 用好这三种功能可以很好地控制程序的结束方式

JS中有趣的知识

1.分号与换行 function fn1(){ return { name: 'javascript' }; } function fn2(){ return { name: 'javascript' }; } var obj1 = fn1(); var obj2 = fn2(); console.log(obj1); console.log(obj2); 这个例子看上去没有什么不同,但是实质上,确实是不同的.第一个输出结果为一个object ,而第二个输出结果为undefined.为什么? 因

有趣的数

有趣的数 问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高位数字不为0. 因此,符合我们定义的最小的有趣的数是2013.除此以外,4位的有趣的数还有两个:2031和2301. 请计算恰好有n位的有趣的数的个数.由于答案可能非常大,只需要输出答案除以1000000007的余数. 输入格式 输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 100