编译原理-西安交通大学(冯博琴)2 词法分析 3.0

合集下载

西电编译原理_复习与试题讲解

西电编译原理_复习与试题讲解

三、计算题(3.4) 2.最小化DFA:(利用可区分概念) 原始划分(两个组):1={A,B} 2={C,D} 考察所有状态转移: move(A,a) = A, move(B,a) = B move(A,b) = B, move(B,b) = C move(C,a) = D, move(D,a) = C move(C,b) = D, move(D,b) = C 根据可区分概念将1分割成两个组1和3,得到: 1={A} 2={C,D} 3={B} 由于状态 C 和D 不可区分,因此可将 C、D 合并为 一个状态且选C作代表,得到最小DFA如右。 对应的图形表示如下。
T F a T + F F b c
三、计算题(3.2)
E E * T F ( E ) T T + F
F d
T F id
(T+F)*id 的分析树
a*b+c*d的分析树
15
三、计算题(3.2) (d) E→E*T|T,T→T+F|F,F→id的识别活前缀的DFA:
E’→.E I0 E E’→E. I1 * E→E.*T E→.E*T E→.T T→.T+F T E→T. I2 T→.F T→T.+F F→.id F F T→F. I3 id id F→id. I4 id
复习什么?
1. 2. 3. 4. 概述 词法分析 语法分析 语法制导翻译生成中间代码 语法与语义、属性 语义规则的两种表现形式:语法制导定义、翻译方案 中间代码:特点,为什么需要中间代码,常见中间代码 形式(后缀式、树、三地址码) 符号表:作用 声明语句的翻译:查填符号表 变量声明 过程声明(左值、右值、作用域、参数传递) 可执行语句的翻译:生成中间代码 算术表达式与赋值语句; 数组元素的引用:地址计算(不变部分、可变部分) 布尔表达式的短路计算翻译; 拉链与回填; 4 控制语句的翻译

奥鹏西安交通大学2020年3月课程考试《编译原理》参考资料答案

奥鹏西安交通大学2020年3月课程考试《编译原理》参考资料答案

西安交通大学课程考试复习资料单选题1.有文法G=({S},{a},{S→SaS,S→ε},S),该文法是( )。

A.LL(1)文法B.二义性文法C.算符优先文法D.SLR(1)文法;答案: B2.正规表达式(ε|a|b)2表示的集合是( )A.{ε,ab,ba,aa,bb}B.{ab,ba,aa,bb}C.{a,b,ab,aa,ba,bb}D.{ε,a,b,aa,bb,ab,ba}答案: D3.以( )作为输出,允许自程序单独编译。

A.绝对机器代码B.可再定位机器语言C.汇编语言程序D.中间语言答案: B4.Fortran语言的编译程序采用( )分配策略。

A.静态B.最佳C.堆式动态D.栈式动态答案: A5.两个不同过程的活动,其生存期是( )。

A.重叠的,不嵌套的B.不重叠的,嵌套的C.重叠的,嵌套的D.不重叠的,不嵌套的答案: B6.表达式作为实在参数可以传递给被调用的过程,替换过程体中的( )。

A.局部变量B.形式参数C.全局变量D.实在参数答案: B7.编译程序使用( )区别标识符的作用域。

A.说明标识符的过程或函数名B.说明标识符的过程或函数的静态层次C.说明标识符的过程或函数的动态层次D.标识符的行号答案: B8.表达式-a+b*(-c+d)的逆波兰式是( )。

A.ab+-cd+-*B.a-b+c-d+*C.a-b+c-d+*D.a-bc-d+*+答案: D9.使用三元式是为了( )。

A.便于代码优化处理B.避免把临时变量填入符号表C.节省存储代码的空间D.提高访问代码的速度答案: B10.为了便于优化处理,三地址代码可以表示成( )。

A.三元式B.四元式C.后缀式D.间接三元式答案: D11.布尔表达式计算时可以采用某种优化措施,比如A and B用if-then-else可解释为( )。

A.if A then true else BB.if A then B else false;C.if A then false else true;D.if A then true else false;答案: B12.对应于产生式A→XY继承属性Y.y的属性计算,可能正确的语义规则是( )。

编译原理及实践冯博琴冯岚教程中文版课后答案

编译原理及实践冯博琴冯岚教程中文版课后答案

编译原理及实践冯博琴冯岚教程中文版课后答案解释术语:1.翻译程序:是一种系统程序,它将计算机编程语言编写的程序翻译成另外一种计算机语言的一般来说等价的程序,主要包括编译程序和解释程序,汇编程序也被认为是翻译程序。

编译程序:也称为编译器,是指把用高级程序设计语言书写的源程序,翻译成等价的机器语言格式目标程序的翻译程序。

编译程序属于采用生成性实现途径实现的翻译程序。

它以高级程序设计语言书写的源程序作为输入,而以汇编语言或机器语言表示的目标程序作为输出。

编译出的目标程序通常还要经历运行阶段,以便在运行程序的支持下运行,加工初始数据,算出所需的计算结果。

2.解释程序:是一种语言处理程序,在词法、语法和语义分析方面与编译程序的工作原理基本相同,但在运行用户程序时,它直接执行源程序或源程序的内部形式(中间代码)。

因此,解释程序并不产生目标程序,这是它和编译程序的主要区别。

源程序:也称源代码,是指未编译的按照一定的程序设计语言规范书写的文本文件,是一系列人类可读的计算机语言指令。

在现代程序语言中,源代码可以是以书籍或者磁带的形式出现,但最为常用的格式是文本文件,这种典型格式的目的是为了编译出计算机程序。

计算机源代码的最终目的是将人类可读的文本翻译成为计算机可以执行的二进制指令,这种过程叫做编译,通过编译器完成。

3.目标程序:又称为“目的程序”,是源程序经编译可直接被计算机运行的机器码集合,在计算机文件上以.obj作扩展名----由语言处理程序(汇编程序,编译程序,解释程序)将源程序处理(汇编,编译,解释)成与之等价的由机器码构成的,计算机能够直接运行的程序,该程序叫目标程序。

目标代码尽管已经是机器指令,但是还不能运行,因为目标程序还没有解决函数调用问题,需要将各个目标程序与库函数连接,才能形成完整的可执行程序。

遍:把对源程序或其等价的中间表示形式从头到尾扫描并完成规定任务的过程。

4.前端:编译前端包括词法分析,语法分析,语义分析和中间代码生成,以及部分代码优化工作,是对源程序进行分析的过程,它主要与源语言有关,与目标机无关,主要根据源语言的定义静态分析源程序的结构,以检查是否符合语言的规定,确定原源程序所表示的对象和规定的操作,并以某种中间形式表示出来。

西安交大编译原理词法分析器实验报告

西安交大编译原理词法分析器实验报告

编译原理课内实验报告学生姓名石磊专业/班级计算机26学号2120505140所在学院电信学院提交日期2014-10-2一:实验目的:1. 强化对系统软件综合工程实现能力的训练;2.加强对词法分析原理、方法和基本实现技术的理解;二:实验内容用C语言或者其他的高级语言作为宿主语言完成C1语言的词法分析器的设计和实现。

三:实验功能描述该程序要实现的是一个读单词的过程,从输入的源程序中,识别出各具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。

并依此输出各个单词的内部编码以及单词符号自身的意义。

四:设计思想设计该词法分析器的过程中虽然没有实际将所有的状态转移表建立出来,但是所用的思想是根据状态转移表来实现对单词的识别。

首先构造一个保留字表,然后每输入一个字符就检测应该进入什么状态,并将该字符连接到d串后继续输入。

如此循环,最后根据所在的接受状态以及保留字表识别单词。

五:实验程序代码C0语言如下:%{#include <stdio.h>#include <stdlib.h>#include <string.h>int yywrap();int lineno=1;%}delim [ \t]ws {delim}+letter [A-Za-z]digit [0-9]id {letter}({letter}|{digit})*number {digit}+error_id ({digit})+({letter})+enter [ \n]spchar ("{"|"}"|"["|"]"|"("|")"|";"|"="|",")ariop ("+"|"-"|"*"|"/")relop ("<"|"<="|">"|">="|"=="|"!=")comment \/\*(\*[^/]|[^*])*\*\/reswd (int|else|return|void|if|while|include)%%{ws} {}{comment} {}{enter} {lineno++;}{reswd} {fprintf(yyout,"%d 行\t 关键字\t%s\n",lineno,yytext);}{spchar} {fprintf(yyout,"%d 行\t 标识符\t%s\n",lineno,yytext);}{id} {fprintf(yyout,"%d 行\t 保留字\t%s\n",lineno,yytext);}{number} {fprintf(yyout,"%d 行\t 数字\t%s\n",lineno,yytext);}{error_id} {fprintf(yyout,"%d 行\t 出错\t%s\n",lineno,yytext);}{ariop} {fprintf(yyout,"%d 行\t 左括号\t%s\n",lineno,yytext);}{relop} {fprintf(yyout,"%d 行\t 右括号\t%s\n",lineno,yytext);}%%int yywrap() {return 1;}int main(void){yylex();return 0;}cmd 运行截图:测试程序如下:#include <stdio.h>int main() { int a,b,c; if(a>b) {c=a;a=b; b=c }return 0;}分析结果如下:#1行关键字include 1行右括号<1行保留字stdio .1行保留字h1行右括号>2行关键字int2行保留字main 2行标识符(2行标识符)3行标识符{4行关键字int4行保留字a4行标识符,4行保留字b4行标识符,4行保留字c4行标识符;5行关键字if5行标识符(5行保留字a 5行右括号>5行保留字b5行标识符)6行标识符{6行保留字c6行标识符=6行保留字a6行标识符;7行保留字a7行标识符=7行保留字b7行标识符;8行保留字b8行标识符=8行保留字c9行标识符}10行关键字return 10行数字010行标识符;11行标识符}C程序实现程序代码如下:#include<stdio.h>#include<string.h>void main(){int i=0,j,k=0,state=1,f=0,linenum=1;chara[11][10]={"const","var","call","begin","if","while","do","odd","end","then","proced ure"};char b,d[40]={"\0"};freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);b=getchar();while(b!=EOF)/*判断所输入字符是否为结束符*/{if(b==' '||b=='\n'||b=='\t')/*滤过空格、换行等分隔符号*/{ if(b='\n') linenum++;b=getchar();}else if((b>='a'&&b<='z')||(b>='A'&&b<='Z'))/*识别标识符以及保留字*/{d[i++]=b;b=getchar();while((b>='a'&&b<='z')||(b>='A'&&b<='Z')||(b>='0'&&b<='9')) {d[i++]=b;b=getchar();}for(j=0;j<11;j++)/*查询保留字表确定该单词是否是保留字*/ { if(strcmp(d,a[j])==0){ printf("保留字:%s\n",d);k=1;break;}}if(k==0)/*在保留字表中没有查到该单词,是标识符*/printf("标识符:%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;k=0;}else if(b>='0'&&b<='9')/*识别常数*/{ d[i++]=b;b=getchar();while(f!=1){switch (state) {case 1:if(b>='0'&&b<='9') {state=1;d[i++]=b;b=getchar();}else if(b=='.') { state=2;d[i++]=b;b=getchar();}else if(b=='E') { state=4;d[i++]=b;b=getchar();}else state=7;break;case 2:if(b>='0'&&b<='9') {state=3;d[i++]=b;b=getchar();}else state=8;break;case 3:if(b>='0'&&b<='9') {state=3;d[i++]=b;b=getchar();}else if(b=='E') { state=4;d[i++]=b;b=getchar();}else state=7;break;case 4:if(b=='+'||b=='-') { state=5;d[i++]=b;b=getchar();}else if(b>='0'&&b<='9'){ state=6;d[i++]=b;b=getchar();}else state=8;break;case 5:if(b>='0'&&b<='9'){ state=6;d[i++]=b;b=getchar();}else state=8;break;case 6:if(b>='0'&&b<='9'){ state=6;d[i++]=b;b=getchar();}else state=7;break;case 7: f=1;break;case 8: f=1;break;}}if(state==7&&(b<'a'||b>'z')&&(b<'A'||b>'Z'))printf("常数:%s\n",d);else if(state==7&&(b>='a'&&b<='z')||(b>='A'&&b<='Z'))/*数字后接字母的出错控制*/{while((b>='a'&&b<='z')||(b>='A'&&b<='Z')){ d[i++]=b;b=getchar();}printf("error line %d\n",linenum);}else printf("error line %d\n",linenum);for(j=0;j<=i;j++)d[j]='\0';i=0;f=0;state=1;}else if(b=='<')/*识别'<'、'<='和'<>'*/{ d[i++]=b;b=getchar();if(b=='='||b=='>'){ d[i++]=b;b=getchar();printf("结束运算符:%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}else{ printf("开始运算符:%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}}else if(b=='>')/*识别'>'和'>='*/{ d[i++]=b;b=getchar();if(b=='='){ d[i++]=b;b=getchar();printf("运算符:%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}else{ printf("终结运算符:%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}}else if(b==':')/*识别':='*/{ d[i++]=b;b=getchar();if(b=='='){ d[i++]=b;b=getchar();printf("赋值运算符:%s\n",d);}else printf("error line %d\n",linenum); for(j=0;j<=i;j++)d[j]='\0';i=0;}else if(b=='*'||b=='+'||b=='-'||b=='/'||b=='=')/*识别运算符*/{ printf("算术运算符:%c\n",b);b=getchar();}else if(b=='('||b==')'||b==','||b==';'||b=='.')/*识别分隔符*/{ printf("分隔符:%c\n",b);b=getchar();}else{ printf("error line %d\n",linenum);b=getchar();}}}测试程序如下:#include <stdio.h> int main(){int a,b,c; if(a>b){c=a;a=b;b=c}return 0;}分析输出结果如下:error line 1标识符:include 开始运算符:< 标识符:stdio 分隔符:.标识符:h终结运算符:> 标识符:int标识符:main 分隔符:(分隔符:) error line 5标识符:int标识符:a 分隔符:,标识符:b分隔符:,标识符:c分隔符:;保留字:if分隔符:(标识符:a终结运算符:>标识符:b分隔符:)error line 9标识符:c算术运算符:=标识符:a分隔符:;标识符:a算术运算符:=标识符:b分隔符:;标识符:b算术运算符:=标识符:cerror line 12标识符:return常数:0分隔符:;error line 15六:实验心得在本次实验中,我耗费了大量时间来设计分析设计。

编译原理-西安交通大学(冯博琴)2_词法分析_3.0

编译原理-西安交通大学(冯博琴)2_词法分析_3.0

对于如上的状态转换图,状态0的代码如下所示:
state 0: C := GETCHAR ; if LETTER(C) then goto state 1 else FAIL( )
0
字母或数字
字母 1
其他
*
2
算 ‘D只 分界CE数D术 =要 界中符LI它过IG、 ’碰 符M的,I返程IT逻 、TT到一字它R(E,回辑‘标般符)R返U是当真(E符;识为C是回布。且假)号’符:是数T尔仅值R,、后空过字函U当括‘的格程,E。号.分、,’ 、、
单词符号识别的简单方法:超前搜索。 关键字识别:
例如:在标准FORTRAN中 1、DO99K = 1,10 2、IF(5.EQ.M)I = 10 3、DO99K = 1.10 4、IF(5) = 55
其中的DO、 IF为关键字
其中的DO、 IF为标识符 的一部分
标识符的识别
多数语言的标识符是字母开头的“字母/数字”串, 而且在程序中标识符的出现后都跟着算符或界符。因此, 不难识别。
状态转换图的功能:用于识别一定的字符串。
初态:一张转换图的启动条件,至少有一个,用圆圈表示。
终态:一张转换图的结束条件,至少有一个,用双圈表示。
* :表示多读进了一个字符。
例2-3:简单的状态转换图示例:
1
X2
初态
从0状态到1状态 可能出现字母
字母或数字
终态
0
字母 1
其他 2 * 0
(b)识别标识符的转换图
常数的识别
对于某些语言的常数的识别也需要使用超前搜索。
算符和界符的识别
对于诸如C++语言中的“+ +”、“- -”,这种复 合成的算符,需要超前搜索。

西安交大编译原理语法分析器实验报告

西安交大编译原理语法分析器实验报告

编译原理课内实验报告学生姓名石磊专业/班级计算机26学号2120505140所在学院电信学院提交日期2014-12-2一:实验目的:1.强化对系统软件综合工程实现能力的训练;2.加强对语法分析原理、方法和基本实现技术的理解;二:实验内容1.用C语言或者其他的高级语言作为宿主语言完成C0语言的词法分析器的设计和实现。

2.针对if语句的文法编写一个递归下降分析程序,输出结果为抽象语法树。

注意,if语句文法中的表达式E采用四则运算表达式的文法;抽象语法树的格式自行设计,如果需要降低难度的话,也可用具体语法树而不用抽象语法树作为输出。

三:实验功能描述语言的语法分析器的源程序并调试通过。

其中语法分析程序既可1.编写C以自己手动去完成,也可以利用YACC自动生成。

2. 通过测试程序的验收;四:功能描述:该语法分析器用yacc生成,针对if语句的文法编写的向下递归程序,输出结果为语法树,实现了实验目标,达到了实验要求。

五:实验程序代码%{#include <string.h>#include <stdlib.h>#include "yystype.h"#include "y.tab.h"#include "treedisp.h"int yycount = 0;extern YYSTYPE yylval;#define NSYMS 20struct symtab {char *name;double value;} symtab[NSYMS];struct symtab *symlook(char *s);#define NRSVS 10struct rsvtab {char *name;int id;} rsvtab[NRSVS] = {{"if", IF},{"else", ELSE},{"while", WHILE},{"for", FOR},{"other", OTHER},{"var", VAR}};int rsvlook(char *s);%}digit [0-9]integer {digit}+eq "=="pl "+"mi "-"mu "*"di "/"sc ";"as "="identifier [a-zA-Z][a-zA-Z0-9_]*delim [ \n\t]ws {delim}+other "other"%%{integer} {//yylval = atoi(yytext);rec_token("INTEGER");return INTEGER;}{identifier} {if (rsvlook(yytext) != 0) {rec_token("RESERVED");return rsvlook(yytext);}rec_token("SYMBOL");return SYMBOL;{eq} { rec_token("OPR"); return EQ; } {pl} { rec_token("OPR"); return PL; } {mi} { rec_token("OPR"); return MI; } {mu} { rec_token("OPR"); return MU; } {di} { rec_token("OPR"); return DI; } {as} { rec_token("OPR"); return ASSIGN; } {sc} { rec_token("SC"); return SC; }\( { rec_token("LB"); return LB; }\) { rec_token("RB"); return RB; }{ws} ;. {printf("error: %s\n", yytext);yyerror("Illigal input.");}%%char *buffer[20];void rec_token(char *s) {yylval.token_id = ++yycount;yylval.text = strdup(yytext);sprintf(buffer, "%s(%s)", s, yytext);name_node(yycount, buffer);}int rsvlook(char *s) {struct rsvtab *sp;for (sp = rsvtab; sp < &rsvtab[NRSVS]; ++sp) { if (sp->name && !strcmp(sp->name, s))return sp->id;}return 0;}struct symtab *symlook(char *s) {struct symtab *sp;for (sp = symtab; sp < &symtab[NSYMS]; ++sp) { if (sp->name && !strcmp(sp->name, s))return sp;if (!sp->name) {sp->name = strdup(s);return sp;}}yyerror("Too many symbols.");exit(1);}测试代码:if (1+1)if (2*3+5)if (3*4+9)if (5*3+2)other;elseother;elseother;elseother;elseb=2*3+5;测试结果:stseq├── statement│└── mifst│├── RESERVED(if)│├── LB(()│├── exp││└── term││└── factor││└── INTEGER(1)│├── RB())│├── mifst││├── RESERVED(if)││├── LB(()││├── exp│││├── term││││├── term│││││└── factor│││││└── INTEGER(2) ││││├── OPR(*)││││└── factor││││└── INTEGER(3)│││├── OPR(+)│││└── exp│││└── term│││└── factor│││└── INTEGER(5) ││├── RB())││├── mifst│││├── RESERVED(if)│││├── LB(()│││├── exp││││├── term│││││├── term││││││└── factor││││││└── INTEGER(3)│││││├── OPR(*)│││││└── factor│││││└── INTEGER(4)││││├── OPR(+)││││└── exp││││└── term││││└── factor││││└── INTEGER(9)│││├── RB())│││├── mifst││││├── RESERVED(if)││││├── LB(()││││├── exp│││││├── term││││││├── term│││││││└── factor│││││││└── INTEGER(5) ││││││├── OPR(*)││││││└── factor││││││└── INTEGER(3)│││││├── OPR(+)│││││└── exp│││││└── term│││││└── factor│││││└── INTEGER(2) ││││├── RB())││││├── statement│││││├── RESERVED(other)│││││└── SC(;)││││├── RESERVED(else)││││└── statement││││├── RESERVED(other)││││└── SC(;)│││├── RESERVED(else)│││└── statement│││├── RESERVED(other)│││└── SC(;)││├── RESERVED(else)││└── statement││├── RESERVED(other)││└── SC(;)│├── RESERVED(else)│└── mifst│├── SYMBOL(b)│├── OPR(=)│├── exp││├── term│││├── term││││└── factor││││└── INTEGER(2)│││├── OPR(*)│││└── factor│││└── INTEGER(3)││├── OPR(+)││└── exp││└── term││└── factor││└── INTEGER(5)│└── SC(;)└── stseq└── (empty)六:实验心得在本次实验中,我耗费了大量时间来设计分析设计。

西安交通大学编译原理课件

西安交通大学编译原理课件

E→E+a|a E⇒E+a ⇒E+a+a ⇒… L(G)={a,a+a,a+a+a,…}
5
上下文无关文法回顾
A→Aa|a A→aA|a
L(G)={an|n为整数,n≥1}
A→Aα|β A→αA|β
A→ε
β不以A开头 L(G)={βαn|n为整数,n≥0}
L(G)={ε,…}
A→Aa|ε A→aA|ε
10
Parse Trees and Abstract Syntax Trees
推导:从开始符号起构造特定句子的一个方法 推导:不能够唯一地表示所推到出的句子的结构
11
上下文无关文法回顾
exp→exp op exp|(exp) | number op →+|-|*
(number – number) * number
15
exp⇒exp op exp ⇒(exp) op exp ⇒(exp op exp) op exp ⇒(number op exp) op exp ⇒(number - exp) op exp ⇒(number - number) op exp ⇒(number - number) * exp ⇒(number - number) * number
typedef struct streenode
{ ExpKind kind;
OpKind op;
struct streenode *lchild, *rchild;
int val;
} StreeNode;
typedef StreeNode *SyntaxTree;
18
Yinliang Zhao (赵银亮)

西安交通大学《编译原理》第二章 期末考试拓展学习7

西安交通大学《编译原理》第二章 期末考试拓展学习7

西交《编译原理》第二章词法分析C# 语言规范输入产生式定义 C# 源文件的词法结构。

C# 程序中的每个源文件都必须符合此词法文法产生式。

input:(输入:)input-sectionopt(输入节可选)input-section:(输入节:)input-section-part(输入节部分)input-section input-section-part(输入节输入节部分)input-section-part:(输入节部分:)input-elementsopt new-line(输入元素可选新行)pp-directive(pp 指令)input-elements:(输入元素:)input-element(输入元素)input-elements input-element(输入元素输入元素)input-element:(输入元素:)whitespace(空白)comment(注释)token(标记)C# 源文件的词法结构由五个基本元素组成:行结束符、空白、注释、标记和预处理指令。

在这些基本元素中,只有标记在 C# 程序的句法文法中具有重要意义。

对C# 源文件的词法处理就是将文件缩减成标记序列,该序列然后即成为句法分析的输入。

行结束符、空白和注释可用于分隔标记,预处理指令可导致跳过源文件中的某些节,除此之外这些词法元素对 C# 程序的句法结构没有任何影响。

当有若干词法文法产生式与源文件中的一个字符序列匹配时,词法处理总是构成尽可能最长的词法元素。

例如,字符序列 // 按单行注释的开头处理,这是因为该词法元素比一个 / 标记要长。

行结束符行结束符将 C# 源文件的字符划分为行。

new-line:(新行:)回车符 (U+000D)换行符 (U+000A)回车符 (U+000D) 后跟换行符 (U+000A)行分隔符 (U+2028)段落分隔符 (U+2029)为了与添加文件尾标记的源代码编辑工具兼容,并能够以正确结束的行序列的形式查看源文件,下列转换按顺序应用到 C# 程序中的每个源文件:如果源文件的最后一个字符为 Control-Z 字符 (U+001A),则删除此字符。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

4、GETBC
过程,检查CHAR中的字符是否为空白。若是,则调用GETCHAR
直至CHAR中进入一个非空白字符。
5、CONCAT
过程,把CHAR中的字符连接到TOKEN之后。
6、LETTER
DIGIT 7、RESERVE
布尔函数过程,它们分别判断CHAR中的字符是数字或是字母,
从而给出真假值TRUE、FALSE。 整型函数过程,用TOKEN中的字符串查保留字表,若是一个保留
转换图:是一张有限方向图。在状态转换图中,结点代表 状态,用圆圈表示。状态之间用箭弧连接。箭弧上 的标记(字符)代表在射出结状态下可能出现的输 入字符或字符类。 状态转换图的功能:用于识别一定的字符串。 初态:一张转换图的启动条件,至少有一个,用圆圈表示。 终态:一张转换图的结束条件,至少有一个,用双圈表示。 * :表示多读进了一个字符。
确定
1、关键字:由程序语言定义的具有固定意义的标识符。也 可称为保留字或基本字。例如:Pascal中的begin, end,if等。它是确定的。 2、标识符:用来表示各种名字,如变量名、数组名、过程 名等。它是不限的。
3、常数:常数的类型一般有整型、实型、布尔型、文字型 等。它是不限的。
不限
4、运算符:如+、-、*、/ 等。它是确定的。
字母 数字
j
k
i
/
l
字符变量,存放最新 读进的源程序字符。
例2-7:示例——如何把状态结对应于一段程序:
字母或数字 字母 其他
0
1
2
*
FAIL( )是例子程序, LETTER( )是布尔 它移回先行指针 函数过程,当且仅 (lookahead 当C中的字符是字 pointer), 开始下一 母,它返回真假值 状态转换图,或调用 TRUE。 出错程序。
例2-6:以下CASE语句段对应的状态图:
state i: GETCHAR; CASE CHAR OF ‘A’..‘Z’:„ state ‘0’..‘9’:„ state ‘/’ END; FAIL :„ state j „ ; k „ ; l „ ;
过程,将下一输入字 符读入CHAR,搜索指 示器前移一个字符。
DELIMITER(C)是过程,
对于如上的状态转换图,状态1的代码如下所示:
state 1: C := GETCHAR ; if LETTER( C) or DIGIT(C)
then goto state 1 else if DELIMITER(C)
then goto state 2
else FAIL( )
字则给予编码,否则回送0值(假定0不是保留字的编码)。
8、RETRACT 过程,把搜索指示器回调一个字节,把CHAR中的字符置为空白。
以上函数和子程序过程都不难编制,使用它们能够方便 的构造状态转换图的对应程序。一般,我们可以让每一个状 态结对应一个程序段。 例如:我们可以让不含回路的分叉结,对应一个CASE 语句,或者是一组IF„THEN„ELSE语句。具体见后面实例。 终态结一般对应一个RETURN(C,VAL)语句。其中C为单词 种别编码;VAL是字符数组的TOKEN ,或者是一个整数值, 或者无定义。具体见后面实例。
注意:一个语言的单词符号如何分种,分几种,怎样编码,是一个技术
问题。标识符一般同归为一种。常数则宜按类型(整、实、布尔)分。 关键字可以将其全体视为一种,也可一字一种。运算符可采用一符一种, 但也可把具有一定共性的视为一种。界符则一般采用一符一种。如何进 行分种主要取决于处理上的方便。 若是一符一种分种,单词自身值就不需要了。否则,要查符号表。
对于如上的状态转换图,状态0的代码如下所示:
state 0: C := GETCHAR ;
if LETTER(C) then goto state 1
else FAIL( )
字母或数字 字母 其他
0
1
2
*
DIGIT( )是布尔函 只要碰到标识符后的分 数过程,当且仅当 界符,它返回TRUE。 C中的字符是数字, 分界符一般为:空格、 它返回真假值 算术、逻辑符号,括号、 TRUE。 ‘=’、‘;’、‘.’ 、 ‘,’。
的。 常数的类型一般有整型、实型、 布尔型、文字型等。它是不限 的。 运算符:如+、-、*、/ 等。 它是确定的。 界符:如逗号、分号、括号、 /*,*/ 等。它是确定的。
1、关键字
源 程 序
2、标识符
扫描器
3、常数
scanner
4、运算符
5、界符
词法分析器的功能:输入源程序,输出单词符号。 单词符号:一个程序语言的基本语法符号。分为以下5种。
GETCHAR是过程,
将下一输入字符读入 为了把状态转换图转化成程序,每个状态要建立一段
程序,它要做的工作如下:
CHAR,搜索指示器 前移一个字符。
第一步:从输入缓冲区中取一个字符。为此,我们使用函 数GETCHAR,每次调用它,推进先行指针,送回一 个字符。 第二步:确定在本状态下,哪一条箭弧是用刚刚来的输入 字符标识的。如果找到,控制就转到该弧所指向 的状态;若找不到,那么寻找该单词的企图就失 败了。 失 败:先行指针必须重新回到开始指针处,并用另一状 态图来搜索另一单词。如果所有的状态转换图都 试过之后,还没有匹配的,就表明这是一个词法 错误,此时,调用错误校正程序。
例2-2 :下述C++代码段:while ( i >= j ) i - -; 经词法分析器处理以后,它将被转换为如下的单词符号串
( while ,_ ) ( ( ,_ ) ( id ,指向i的符号表指针 ) ( >= ,_ )
( id ,指向j的符号表指针 )
( ) ,_ ) ( id ,指向i的符号表指针 )
5、界符:如逗号、分号、括号、/*,*/ 等。它是确定的。
单词符号的表示形式:词法分析器所输出的单词符号常常表示成
二元式(单词种别,单词自身的值)。 单词种别可以用以下形式表示: 1、一类单词统一用一个整数值代表其属性。例如:1代表关键字, 2代表标识符等。 2、每一个单词一个类别。例如:1代表BEGIN,2代表END等。 单词自身的值可以表示成:常量的二进制表示;常量、变量等在符号表 种的地址码,等等。
其中的DO、 IF为关键字 其中的DO、 IF为标识符 的一部分
标识符的识别
多数语言的标识符是字母开头的“字母/数字”串, 而且在程序中标识符的出现后都跟着算符或界符。因此, 不难识别。 常数的识别 对于某些语言的常数的识别也需要使用超前搜索。
算符和界符的识别
对于诸如C++语言中的“+ +”、“- -”,这种复 合成的算符,需要超前搜索。
修改之后,状态2的代码如下所示: 对于如上的状态转换图,终态——状态2 的代码如下所示: state 2: RETRACT( ) ;
state 2: RETRACT( ) ; c := RESERVE( ); RETURN($id if c = 0 ,INSTALL( ) ) then else
字母或数字 字母 其他
0
1
2
*
INSTALL( )是过程, RESERVE( ) 整型函数 如我们识别出的标 如果同时识别 过程,针对TOKEN中的 RETRACT( )是过程, 识符不在符号表中, 字符串进行查找,看其 标识符和定义符, 由于分界符不属于 我们把它装入符号 是否是保留字,是保留 则需要修改为 标识符,所以我们 字给出它的编码,否则 表。我们还要给语 State2: 要把先行指针回调 回送0(假定0不是保留 法分析程序返回一 字编码)。 一个字符。 个二元式。
起点指示器 搜索指示器 起点指示器 搜索指示器 起点指示器
120个字符
输入缓冲区 输入缓冲区
两 个 互 补 输 入 缓 冲 区
单词符号识别的简单方法:超前搜索。 关键字识别: 例如:在标准FORTRAN中 1、DO99K = 1,10 2、IF(5.EQ.M)I = 10 3、DO99K = 1.10 4、IF(5) = 55
若识别输入语句 IF (5.EQ.M) GOTO 100,若缓冲区情况如下所示: 扫描缓冲区的结构: •
• • 缓冲区大小:120个字符。 采用两个指示器:起点指示器、搜索指示器。 两个互补区。
TO 100
TO 100
搜索指示器
IF (5.EQ.M) GO IF (5.EQ.M) GO IF (5.EQ.M) GO
字母或数字
字母 1 数字 3 5 6 7 1 0 1 1 1 2 1 3 非字母与数字
*
2
数字 = +
非数字
*
4
*
。 。
非* *
8 9
*


) 其他
1、CHAR
2、TOKEN 3、GETCHAR
字符变量,存放最新读进的源程序字符。
字符数组,存放构成单词的字符串。 过程,将下一输入字符读入CHAR,搜索指示器前移一个字符。
例2-1:151-FORTRAN编译程序的词法分析器在扫描输入串 IF (5·EQ·M) GOTO 100
逻辑IF 左括号 整常数 等号 标识符 右括号 GOTO 标号 (34,_)
后,它输出的单词符号串是:
IF为关键字,种别编码34, 采用一符一种的编码方式。 ‘(’为界符,种别编码2,采 (2,_) 用一符一种的编码方式。 常数类型,种别编码20,单词自 (20,‘5’的二进制表示) 身的值为‘5’的二进制表示。 等号为运算符,种别编码6, (6,_) 采用一符一种的编码方式。 M为标识符,种别编码26,单 (26,‘M’) 词自身值为‘M’。 ‘)’为界符,种别编码16, (16,_) 采用一符一种的编码方式。 GOTO为关键字,种别编码30, (30,_) 采用一符一种的编码方式。 100为标号,种别编码19,单词 (19,‘100’的二进制表示) 内部的值用100的二进制表示。
相关文档
最新文档