从lex&yacc到编译器
Lex和Yacc从入门到精通(PDF)

Lex和Yacc从入门到精通熊春雷Abstract在开发程序的过程中经常会遇到文本解析的问题,例如:解析C语言源程序,编写 脚本引擎等等,解决这种文本解析的方法有很多,一种方法就是自己手动用C或者 C++直接编写解析程序,这对于简单格式的文本信息来说,不会是什么问题,但是 对于稍微复杂一点的文本信息的解析来说,手工编写解析器将会是一件漫长痛苦 而容易出错的事情。
本系列文档就是专门用来由浅入深的介绍两个有名的Unix工 具Lex和Yacc,并会一步一步的详细解释如何用这两个工具来实现我们想要的任何 功能的解析程序,为了方便理解和应用,我会在该系列的文章中尽可能的采用具 体可行的实例来加以阐释,而且这种实例都是尽可能的和具体的系统平台无关的 ,因此我采用命令行程序作为我们的解析程序的最终结果。
1、环境配置篇开发Lex和Yacc程序最需要的程序就是lex和yacc了,如果你是Unix或者Linux系统,则 系统自带了这两个工具,无需安装,不过值得说明的是GNU/Linux下面的Lex是flex, 而Yacc则是bison。
另外需要的就是一个C/C++语言编译器,由于我们采用的是GNU的 lex和yacc,所以,理所当然的我们就使用GNU的编译器了,如果是Unix或者Linux系统 ,那么编译器应该已经安装了。
在这里我重点讨论的是Windows系统环境下的Lex和 Yacc程序的开发,至于为什么选择Windows系统作为开发平台,则是为了尽可能的让初 学者容易入门。
1.1.必备工具言归正传,首先列举Windows平台下面Lex和Yacc开发环境所需要安装的程序:1.Lex(flex.exe)和Yacc(bison.exe)环境2.C/C++编译器1.2.flex和bison值得说明的是,flex.exe和bison.exe是UnxUtils包中的文件,已经将许多 Unix/Linux平台的程序都移植到了Windows平台,可以直接到UnxUtils网站下载,下载解压缩之后在系统的PATH环境变量中增加UnxUtils所有的exe文件所在的目录,使 得DOS命令行可以直接搜索到flex.exe和bison.exe,除此之外还需要从网络上下载 bison需要的bison.simple和bison.hairy两个文件,并且还要分别设置环境变量 BISON_HAIRY指向bison.hairy,BISON_SIMPLE指向bison.simple。
lex原理 -回复

lex原理-回复lex原理的基本原理和使用方法一、介绍Lex原理Lex是一个流行的词法分析器生成器,它是由AT&T贝尔实验室的Eric Schmidt和Mike Lesk在1975年开发的。
Lex程序通过读取输入流并将其分解为词素(tokens)序列的方式来处理输入。
它的设计目的是为了将词法分析器的开发过程自动化,并提供一种快速、高效的方法来生成词法分析器。
二、词法分析原理在分析过程中,词法分析器根据预先定义好的规则模式来将输入流分解为词素。
每个词素都有一个与之对应的记号(token),用于表示它所代表的语言单元。
这些规则通常是用一种基于正则表达式的模式语言来描述的。
1. 模式匹配模式匹配是词法分析器的核心原理。
在Lex中,模式是由正则表达式表示的。
词法分析器将按照定义的顺序尝试每个规则,直到找到匹配输入流的最长的模式。
如果多个模式都匹配到了同样长度的最长模式,则将按照定义顺序选择最先被定义的规则。
例如,假设我们有以下两个规则:[0-9]+ { printf("NUM\n"); }[+-] { printf("OP\n"); }当输入流中的文本是"123"时,模式"[0-9]+"会匹配到整个输入,因此词法分析器会将其解释为一个NUM记号,并执行与之对应的操作。
如果输入文本是"+",则模式"[+-]"会匹配到该输入,词法分析器会将其解释为一个OP记号,并执行对应的操作。
2. 动作执行当词法分析器找到与输入流匹配的模式时,将执行与之关联的动作。
这些动作通常是一些C语言代码或其他程序代码片段,用于对匹配的词素进行进一步处理。
例如,在前面的例子中,动作是将识别到的记号打印到控制台。
3. 生成词法分析器使用Lex生成词法分析器主要包括两个步骤:编写词法规则文件和生成词法分析器。
编写词法规则文件时,我们需要定义一系列的词法规则,每个规则用一个模式-动作对来表示。
lex工具实例

翻译规则部分(续)
为避免二义性,在Ri中 若需出现空格、回车或 制表符,则应用‘\s’, ‘\n’,‘\t’表示。 每个代码段Actioni可 引用已定义的常量、全 局变量和外部变量,也 可以调用在辅助函数部 分定义的函数。
注意:Actioni中的C
程序语句多于一条时, 必须用花括号{ }将 它们括起来,否 则,LEX将会报错
词法分析程序的使用
用户可通过调用函数yylex()使用词法分析程序。每调 用yylex()函数一次,yylex()将从输入流中识别一个单词, 并返回一个整型值(被识别出的单词之内部码)。 所谓单词的内部码是指词法分析程序在识别出某一类 单词时所返回的整型数值(也称为类别码),它由用 户自行定义其取值。 例如,用户可定义标识符Id的内部码为300,实型数 RealNo的内部码为450等等。一般说来,用户自定义的 单词类别码应大于256,而小于256的内部码值可用于 字符单词的类别码,用其ASCII码值来表示。如单词 '+'的内部码可定义为‘+’的ASCII码值43。
LEX的命令格式及选项
格式:lex [-ctvn -V -Q[y|n]] [files] 选项: -c 指明动作为C语句(缺省设置). -t 输出到stdout 而不是 lex.yy.c(缺省设置); -v 提供一个两行的统计概述 -n 不输出-v的概述 -V 在stderr上输出lex的版本信息. -Q[y|n] y:在输出文件lex.yy.c上打印版本信息. n:不打印(缺省设置). 若files为多个文件,则被视为一个,若files为空,则使用stdin.
1.声明(declaration)
LEX的声明又可以分两个
LEX

多重入口及其应用(续)
在LEX源程序定义部分,用 关键字%start定义若干所需 的开始条件名:
%start cond1 cond2 … condk
其中,开始条件名出现顺序 是任意的,若一行写不下时, 可用多行进行定义,但每行 必须以%start开头。 对于已定义的开始条件名 condi,其使用方法是将它们 用一对尖括号括起来,置于 某些识别规则的词型正规式r 的左侧,即
<condi>r {...} 它表示当LEX处在条件condi 时此识别规则才起作用。 为了使LEX进入条件condi,用 户须在某个语义动作中设置 一个形如 BEGIN condi; 的语句,其中BEGIN是由LEX 系统为用户提供的一个宏。 当执行此语句后,LEX便处 于condi条件之下,即词法分 析程序下一次将从附加有开 始条件condi的识别规则开始 进行词型匹配。
1.声明(declaration)
LEX的声明又可以分两个
部分:C语言部分和辅助定 义部分 C语言部分被括在LEX的 特殊括号“%{”与“%}”之 间,它必须符合C语言规范。 这部分内容包括C语言程序 的预处理语句(包含的头 文件、常量定义)、类型 其中, Di(i=1,2,…,n)是要定义的一组宏 和变量定义、子程序的声 名字, ri (i=1,2,…,n) 是定义在Σ∪{D1, 明等。其中,常量定义可 …,Di-1}上的正规式,Σ为词法分析 用于定义单词的内部码。 程序要识别单词相应的字符集。
Hale Waihona Puke 其中,用方括号括起来的部分表示一个字符类,[0-9]表示任一数 字字符,即有[0-9]=0|1|2|…|9, 同理,[a-zA-Z]=a|b|…|c|A|B|…|Z 注意,在引用已定义的宏时,需用花括号{ }将其括起来。上例中 可看出宏iden的定义是建立在宏alpha和alnum上的 声明部分还可定义多重入口,我们将在后面作专门的讨论。
(完整版)基于LEX的词法分析器实验报告

定义识别标识符规则
{id}
{printf("%d行",lineno);
printf("%s ID\n",yytext);}//
定义识别错误的字符串规则当开头为数字的后面为字母的字符串时,是错误的标识符。{error_id}
yylex();/*start the analysis*/
printf("ok2\n");
printf(" No of words: %d\n number: %d\n", wordCount, numcount);
return0;
}
int yywrap()
{
return1;
}
2、新建文本文件,更名为b.c,敲入下面代码此为输入源代码
{printf("error:%s\n",yytext);}//以数字开头的字符自动报错定义忽略空格规则
{whitespace}{/*skip whitespace*/}//忽略空格定义忽略回车规则
{enter}
{lineno++;}//遇到回车自动加行号忽略辅助程序集中包括
主函数main()和辅助函数toupper()。程序代码实现
二、实验原理及方法
Lex输入文件由3个部分组成:定义集(definition),规则集(rule)和辅助程序集(auxiliary routine)或用户程序集(user routine)。这三个部分由位于新一行第一列 的双百分号分开,因此,Lex输入文件的格式如下
{definitions}
LEX

LEX(词法分析器生成工具)学习笔记1LEX介绍LEX(Lexical Analyzer Generator)即词法分析器生成工具是1972年贝尔实验室的M.E.Lesk和E.Schmidt在UNIX 操作系统上首次开发的。
GNU同时推出了和LEX完全兼容的FLEX(Fast Lexical Analyzer Genrator)。
下面用到的例子都是基于flex的。
LEX工作原理:LEX通过对源文件的扫描,经过宏替换将规则部分的正则表达式转换成与之等价的DFA,并产生DFA的状态转换矩阵(稀疏矩阵);利用该矩阵和源文件的C代码产生一个名为int yylex()的词法分析函数,将yylex()函数拷贝到输出文件lex.yy.c中。
函数yylex()以在缺省条件下的标准输入(stdin)作为词法分析的输入文件。
定义部分%%规则部分%%用户附加的C语言代码例1:int num_chars=0,num_lines=0;/*定义两个全局变量,一个及字符数,一个记行数.注意:该语句不能顶行*/%%\n ++num_chars++; ++num_lines;. ++num_chars;%%int main(){yylex();printf(“%d,%d”, num_chars,num_lines);}int yywrap()/*文件结束处理函数,当yylex()读到文件结束标记EOF时,调用该函数时会,用户必须提供该函数,否则会提示编译出错 */{return 1;//返回1表示文件扫描结束,不必再扫描别的文件}lex 的输入文件分成三个段,段间用%% 来分隔。
由于必须存在一个规则段,第一个%% 总是要求存在。
模式LEX的模式是机器可读的正则表达式。
表意字符匹配字符. 除换行外的所有字符\n 换行* 0 次或无限次重复前面的表达式+ 1 次或更多次重复前面的表达式? 0 次或1 次出现前面的表达式^行的开始$ 行的结尾a|b a 或者 b(ab)+ 1 次或玩多次重复 ab"a+b"字符串a+b 本身( C 中的特殊字符仍然有效)[] 字符类[^ab] 除a,b外的任意字符[a^b] a, ^, b中的一个[az]从a到z中的任意字符[a\-z] a,-,z中的一个[a-z] a, z 中的一个<EOF>匹配文件结束标记表 1 :简单模式匹配在方括号([])中,通常的操作失去了本来含意。
lex用法
lex用法
"lex"是一种文本分析工具,主要用于编写词法分析器。
它能够根据用户所定义的模式匹配规则,自动生成C语言代码实现词法分析功能。
具体来说,使用"lex"需要以下几个步骤:
1. 编写"lex"文件:该文件包含"lex"语法及模式匹配规则,决定了如何从输入的字符流中识别
和提取出各种符号和单词。
2. 使用"lex"命令编译生成C程序:命令格式为: `lex -o output.c input.l`,其中"output.c"为生成
的C源程序文件,"input.l"为"lex"文件名。
3. 编译并链接生成的C程序:使用C语言编译器(如gcc)编译生成的C源程序文件,并将其与主程序进行链接,形成可执行文件。
4. 运行程序并测试:将待分析的文本输入到程序中,程序会按照模式匹配规则进行词法分析,并输出分析结果。
"lex"的优点在于可以大大简化词法分析器的编写和维护工作,同时也增强了程序的可读性和
可移植性。
它常被用于编写编译器、解释器、文本编辑器等需要对文本内容进行识别和分析的应
用程序中。
浅析“法”和“法律”的区分
浅析“法”和“法律”的区分对“法”和“法律”的比较,从二者的含义上去理解,去区分,会更加明显。
目前学术理论界大多数人认为从古希腊到马克思一直到现在,对“法”的研究中,“法”不同于“法律”,二者之间有区别,有差异。
标签:“法”;“法律”;区分;形而上学什么是法,何为法律,如何去定义它们,如何去界定它们,区分它们,不仅仅拘泥于法学领域,在哲学领域也是很有必要,也有着重要意义。
一、“法”和“法律”概念的来源对“法”和“法律”二者的概念,来源于古罗马时期的“jus”和“lex”这组概念,不过当时并没有作以很大的区别,后来在拉丁文上二者的区分在一定程度上有所体现。
“jus”指抽象的法则、正义、权利;“lex”是指具体的法律,即罗马王政时期国王制定的法律以及共和国时期各立法机关通过的法律。
再后来的德语中“法”和“法律”的区分也比较明显,在德语中用“Recht”来表示“法”、“权利”和“正义”的概念,而用“Gesetz”来表示“法律”的概念。
“jus”与“lex”、“Recht”与“Gesetz”两组概念的区分在英语中很难找到,但在英语中用“Right”来表示普遍的、一般性的“法”,而用“alaw”或“astatute”来表示“法律”。
总体上讲“法”可以用“jus”、“Recht”“Right”与之相对应;而“法律”可以用“lex”、“Gesetz”、“alaw”或“astatute”与之对应。
在对法的研究过程中又形成了一门单独的学科叫“法哲学”。
这一名词盛行于17世纪末、是18世纪初的欧洲德国哲学家莱布尼茨在《法学教学的新方法》中,首先提到“法哲学”这一词。
接着,德国启蒙大师康德与1797年写下了《法学的形而上学》(在当时“形而上学”意即哲学)。
19世纪末,唯心辩证法大师黑格尔于1821年出版了《法哲学原理》,系统地论述了他的法哲学思想。
英国分析法哲学派创始人奥斯丁于1832年发表了《法理学和实在法哲学讲义》。
Lex使用指南
Lex使用指南Lex是由美国Bell实验室等人用C语言开发的一种词法分析器自动生成工具,它提供一种供开发者编写词法规则(正规式等)的语言(Lex语言)以及这种语言的翻译器(这种翻译器将Lex语言编写的规则翻译成为C语言程序)。
Lex是linux下的工具,本实验使用的编译工具是cygwin(cygwin在windows下模拟一个linux环境)下的flex,它与lex的使用方法基本相同,只有很少的差别。
一、Lex的基本原理和使用方法Lex的基本工作原理为:由正规式生成NFA,将NFA变换成DFA,DFA经化简后,模拟生成词法分析器。
其中正规式由开发者使用Lex语言编写,其余部分由Lex翻译器完成.翻译器将Lex源程序翻译成一个名为的C语言源文件,此文件含有两部分内容:一部分是根据正规式所构造的DFA状态转移表,另一部分是用来驱动该表的总控程序yylex()。
当主程序需要从输入字符流中识别一个记号时,只需要调用一次yylex()就可以了。
为了使用Lex所生成的词法分析器,我们需要将程序用C编译器进行编译,并将相关支持库函数连入目标代码。
Lex的使用步骤可如下图所示:生成词法分析器的过程:使用所生成的词法分析器的过程:二、lex源程序的写法:Lex源程序必须按照Lex语言的规范来写,其核心是一组词法规则(正规式)。
一般而言,一个Lex源程序分为三部分,三部分之间以符号%%分隔。
`[第一部分:定义段]%%第二部分:词法规则段[%%第三部分:辅助函数段]其中,第一部分及第三部分和第三部分之上的%%都可以省略(即上述方括号括起的部分可以省略)。
以%开头的符号和关键字,或者是词法规则段的各个规则一般顶着行首来写,前面没有空格。
Lex源程序中可以有注释,注释由/*和*/括起,但是请注意,注释的行首需要有前导空白。
1. 第一部分定义段的写法:定义段可以分为两部分:第一部分以符号%{和%}包裹,里面为以C语法写的一些定义和声明:例如,文件包含,宏定义,常数定义,全局变量及外部变量定义,函数声明等。
legal词根词缀
legal词根词缀
"Legal"这个词源自拉丁语,其词根为"leg-"或"lex",这在拉丁语中表示“法”或“规则”。
前缀"le-"在拉丁语中有“to”的意思,后缀"-al"则表明该词是形容词性质。
因此,"legal"的含义可以理解为“与法律相关的”或“合法的”。
从"legal"派生出来的词有很多。
例如,"illegal"是由否定前缀"il-"和词根"leg-"构成的,表示“非法的”。
此外,诸如"legislate","legislation","legislative","legislator","legitimate "等单词也都源于同一词根,它们分别表示“制定法律”,“立法”,“立法机构”,“立法者”和“合法的”。
再比如,“legal”的名词形式是“legality”,表示“合法性”,而动词形式“legalize”则表示“使合法化”。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Created with novaPDF Printer (). Please register to remove this message.
语法分析数学表达式 或者可能你以前运用过自己的办法来解决过这个程序问题,不过下面我们将通过编译原 理建立的一套文法分析理论,来十分精彩地解决这个算法问题. 首先是建立数学表达式的文法 EBNF.EBNF 文法可以更灵活地表示 BNF,是 BNF 范式文法的 一种扩展.下面是上一篇 javacc 的介绍中使用到的计算表达式的文法. Expression -> Term { Addop Term } Addop -> "+" | "-" Term -> Factor { Mulop Factor } Mulop -> "*" | "/" Factor -> ID | NUM | "(" Expression ")" 我们来看看如何根据这个 EBNF 文法实现一个递归下降的分析程序.大致上来说要分那 么几步来实现.(注意,下面的几个步骤不光是针对本节的数学表达式问题,而是包含所有通 常的递归下降文法分析器的实现) 语法分析实现 Step 建立词法分析 本系列文章开篇第一节就是讲的词法分析相关问题.因为词法分析是语法分析的前提,那么 我们在实现递归下降算法的时候,同样应该把词法分析的实现考虑进去. 本文要处理只是个数学表达式的问题,那么通过上面的文法,可以看到需要识别的词法无非 就是 2 个 ID,NUM 和 4 个运算符号¡ +¡¡ -¡¡ *¡¡ /¡ 以及 2 个括号¡ (¡¡ (¡ .本文没有 对词法分析的自动机原理进行讲解,这部分内容应该在编译原理中讲得比较透彻.所谓自动 机,就是按一定步骤识别每个字符的算法.可以用下面的几个图来表示 ID 和 NUM 的识别自动 机(识别步骤或算法) NUM: 基本算法就是,如果输入的字符是 digit(¡ 0¡ -¡ 9¡ ),那么进入 check 循环,如果输入 还是 digit,那么再跳回循环查看,如果输入是 other(不是¡ 0¡ -¡ 9¡ ),那么就直接 accept, 接收这个串为 NUM 类型的 TOKEN. ID: 同 NUM 一样,当输入的是 letter,那么进入 ID 的有限自动机.只是在进入 check 循环后, 有两种可能都继续留在循环,那就是 digit 和 letter(¡ a¡ -¡ Z¡ ).当输入既不是 digit, 也不是 letter 的时候,就跳出 check 循环,进入 accept,把接收到的字符归结成 ID 类型的 TOKEN. 通过这个有限自动机的图示,我们就很容易写出词法分析程序. 不过在此之前,我们得写出识别 letter 和 digit 的代码.我们建立两个函数 IsLetter 和 IsDigit 来完成这个功能. int IsLetter(char ch) { if(ch >= 'A' && ch <= 'Z') return 1; if(ch >='a' && ch <='z') return 1; return aPDF Printer (). Please register to remove this message.
代码中我没有特别为此非终结符号创建函数.我们直接在代码以¡+¡ || ¡ -¡ 代替 Addop. 代码如下. int expression() { int temp = term(); // 对应文法中的第一个 Term int tokentype; while(*nextchar == '+' || *nextchar == '-') // 对应文法中的{ Addop Term } { tokentype = gettoken(); switch(tokentype) { case PLUS: temp +=term(); break; case MINUS: temp -=term(); break; default: break; } } return temp; } 然后是第二条文法.同样,我也没有特别为 Mulop 特别写一个文法函数,而是直接以¡ *¡ || ¡ \¡ 代替. Term -> Factor { Mulop Factor } 同理,建立如下函数 int term() { int temp; int tokentype; temp = factor(); // 对应文法中的 Factor while(*nextchar == '*' || *nextchar == '\\') // 对应文法中的 {Mulop Factor} { tokentype =gettoken(); switch(tokentype) { case TIMERS: temp *= factor(); break; case OVER: temp /= factor(); break; default:
从 lex&yacc 说到编译器
前言 文法分析中最重要算法是 LL 自顶向下和 LR 自底向上算法.前面几篇文章主要讲解的是 LL 算法的理论和一个 LL 算法的文法分析器 javacc.本文以 LL(1)算法中最简单的一种形式 递归下降算法来分析常规算法问题中的数学表达式问题.同时,本文也介绍手工构造 EBNF 文 法的分析器代码普遍方法.希望本文的实践能对大家实现自己的语法分析器带来帮助. 数学表达式问题 在学习算法的时候,四则混合运算的表达式处理是个很经典的算法问题. 比如这里有个数学表达式¡ 122+2*(11-1)/(3-(2-0))¡ .我们需要根据这个字符串的描述, 然后计算出其结果. Input: 122+2*(11-1)/(3-(2-0)) Output: 142 四则混合运算中还需要考虑到括号,乘除号与加减号的优先运算问题,通常的解决办法就是 使用堆栈.那种常规的算法和 LL 算法有异曲同工之处,更或者说,那么的算法其实是一样的. 传统数学表达式处理算法简介 这个传统算法其实不知不觉地使用 LL(1)算法的精髓.它就是主要依靠栈式的数据结构 分别保存数和符号,然后根据运算符号的优先级别进行数学计算,并将结果保存在栈里面. 传统算法中使用了两个栈.一个是保存数值,暂时就叫值栈. 另一个是保存符号的,叫符号栈. 我们规定一个记号#,来表示栈底.下面我们就来看看如何计算一个简单的表达式 11+2-8*(5-3). 为了显示整个计算过程,我们以下面这个栈的变化图来表示. 符号栈和值栈的变化是根据输入串来进行的.基本上栈的操作可以简单用下面几句话 来说. Start: 1. 如果当前输入串中得到的是数字,则直接压入值栈.然后转到 Start. 2. 如果当前输入串中得到的是符号,那么对符号进行判断. 1)如果符号是¡ +¡ 或者¡ -¡ ,则依次弹出符号栈的符号,计算栈中数值,直到弹出的符号不 是*,/,+,-. 2)如果符号是¡ *¡ 或者¡ /¡ ,则压入符号栈 3)如果符号是¡ (¡ ,则直接压¡ (¡ 入符号栈 4)如果符号是¡ )¡ ,则依照符号栈的顺序弹出符号,计算栈中数值,把结果压入值栈,直到符 号栈顶是¡ (¡ ,最后再弹出¡ (¡ . 最后转到 Start. 3. 如果当前输入串得到的是 EOF(字符串结束符号),则计算栈中数值,知道符号栈没有符 号.
Created with novaPDF Printer (). Please register to remove this message.
// ID 的词法识别分析 if(IsLetter(*nextchar)) { while(IsLetter(*nextchar) || IsDigit(*nextchar)) { *ptoken = *nextchar; nextchar++; ptoken++; } *ptoken ='\0'; printf("gettoken: token = %s\n",token); return ID; } // NUM 的词法识别分析 if(IsDigit(*nextchar)) { while(IsDigit(*nextchar)) { *ptoken = *nextchar; nextchar++; ptoken++; } *ptoken ='\0'; printf("gettoken: token = %s\n",token); return NUM; } return ERROR; } 代码很简单,我没有写多少任何注释.函数中,首先使用了 char *ptoken 记录 token 的首 地址,它为后面的字符串复制(构造 token)所用.同时,在处理代码的第一部分是过滤掉空格, 制表符和换行符.然后是计算符号的词法分析.计算符号就是一个固定的字符号,所以它的识 别很简单,直接用 switch 来判断*nextchar.而后面的 ID,NUM 的识别就是完全按照前面的有 限自动机表示图表来进行编写的.以 ID 的图表来说,ID 的自动机首先是要识别出第一个字符 是 letter,那么我就写了第一行 if(IsLetter(*nextchar)),如果满足,则进入 check 循环, 也就是 while(IsLetter(*nextchar) || IsDigit(*nextchar))循环.循环中我们记录了 *nextchar 到 token 符号中.最后跳出 check 循环,进入 accept,在代码中 return ID.对于 NUM 的词法识别也是如此的,我就不多说了. 2. 根据 EBNF 文法建立文法识别函数 首先看到第一条非终结产生式 Expression -> Term { Addop Term } Expression 也是我们总的输入结果函数.我们先定义函数 int Expression(),其返回值就是 我们要处理的表达式的值.右边的产生式中,第一个是 Term,我们就直接调用 Term 函数完成. 然后是 0 到无限次的 Addop Term,那么用一个循环即可.文法中使用非终结符号 Addop.程序