语法分析器实验报告
- 格式:docx
- 大小:96.42 KB
- 文档页数:21
《词法分析》实验报告目录目录 (1)1 实验目的 (2)2 实验容 (2)2.1 TINY计算机语言描述 (2)2.2 实验要求 (2)3 此法分析器的程序实现 (3)3.1 状态转换图 (3)3.2 程序源码 (4)3.3 实验运行效果截图 (9)4 实验体会 (10)1实验目的1、学会针对DFA转换图实现相应的高级语言源程序。
2、深刻领会状态转换图的含义,逐步理解有限自动机。
3、掌握手工生成词法分析器的方法,了解词法分析器的部工作原理。
2实验容2.1TINY计算机语言描述TINY计算机语言的编译程序的词法分析部分实现。
从左到右扫描每行该语言源程序的符号,拼成单词,换成统一的部表示(token)送给语法分析程序。
为了简化程序的编写,有具体的要求如下:1、数仅仅是整数。
2、空白符仅仅是空格、回车符、制表符。
3、代码是自由格式。
4、注释应放在花括号之,并且不允许嵌套TINY语言的单词2.2实验要求要现编译器的以下功能1、按规则拼单词,并转换成二元式形式2、删除注释行3、删除空白符 (空格、回车符、制表符)4、列表打印源程序,按照源程序的行打印,在每行的前面加上行号,并且打印出每行包含的记号的二元形式5、发现并定位错误词法分析进行具体的要求1、记号的二元式形式中种类采用枚举方法定义;其中保留字和特殊字符是每个都一个种类,标示符自己是一类,数字是一类;单词的属性就是表示的字符串值。
2、词法分析的具体功能实现是一个函数GetToken(),每次调用都对剩余的字符串分析得到一个单词或记号识别其种类,收集该记号的符号串属性,当识别一个单词完毕,采用返回值的形式返回符号的种类,同时采用程序变量的形式提供当前识别出记号的属性值。
这样配合语法分析程序的分析需要的记号及其属性,生成一个语法树。
3、标示符和保留字的词法构成相同,为了更好的实现,把语言的保留字建立一个表格存储,这样可以把保留字的识别放在标示符之后,用识别出的标示符对比该表格,如果存在该表格中则是保留字,否则是一般标示符。
实验5 用语法制导方式生成中间代码生成器魏陈强23020092204168一、实验目的掌握语法制导定义和翻译的原理和技术,在语法分析器的基础上,加上语义分析,构造一个中间代码生成器。
二、实验内容在实验四生成的语法分析器基础上加入语义动作,将源程序翻译为对应的中间代码序列。
三、实验要求1.实验报告中给出采用测试源代码片断,及其对应的三地址码形式(内部表示形式可以自行考虑)。
例如,程序片断对应的中间代码为:四、实验思路在前4次实验的基础上进行中间代码生成的编写,采用linux环境下的lex和yacc工具。
首先编写goto.c函数,该函数实现符号表、回填、创建节点、定义节点属性等功能。
Lex.l文件无需修改,yacc.y文件中,在每个生成式后加上语法制导翻译,主要是依据truelist和falselist 来实现回填功能。
编写完后,在yacc.y中以头文件的方式加入goto.c,编译即可。
五、实验代码1、lex.l%{%}……letter [A-Za-z]digit [0-9]……%option noyywrap%%if { return( IF ); }else { return( ELSE ); }……"<"|"<="|">"|">="|"!="|"==" { op_in(&yylval, yytext); return( REL); }……%%2、Yacc.y%{#include "goto.c"#define YYSTYPE nodeint yyerror();int yyerror(char* msg);extern int yylex();codelist* list;%}%token BASIC NUMBER REAL ID TRUE FALSE%token INT CHAR BOOL FLOAT%token REL%token IF ELSE WHILE DO BREAK SWITCH CASE DEFAULT%token OR AND%left OR%left AND%right '!'%left '+' '-'%left '*' '/'%right UMINUS%right INC DEC%expect 1%%program : block { };block : '{' decls statementlist '}' { };decls : decls decl { }| { };decl : type ID ';' { };type : type '[' NUMBER ']' { }| BASIC { };statementlist : statementlist M statement { backpatch(list, $1.nextlist, $2.instr);$$.nextlist = $3.nextlist; }| statement { $$.nextlist = $1.nextlist; };statement : IF '(' boolean ')' M statement ELSE N M statement{ backpatch(list, $3.truelist, $5.instr);backpatch(list, $3.falselist, $9.instr);$6.nextlist = merge($6.nextlist, $8.nextlist);$$.nextlist = merge($6.nextlist, $10.nextlist); }| IF '(' boolean ')' M statement { backpatch(list, $3.truelist, $5.instr);$$.nextlist = merge($3.falselist, $6.nextlist); }| WHILE M '(' boolean ')' M statement { backpatch(list, $7.nextlist, $2.instr);backpatch(list, $4.truelist, $6.instr);$$.nextlist = $4.falselist;gen_goto(list, $2.instr); }| DO M statement M WHILE '(' boolean ')' M ';' { backpatch(list, $3.nextlist, $4.instr);backpatch(list, $7.truelist, $9.instr);$$.nextlist = $7.falselist;gen_goto(list, $2.instr); }| BREAK ';' { }| '{' statementlist '}' { $$.nextlist = $2.nextlist; }| assignment ';' { $$.nextlist = NULL; };assignment : ID '=' boolean { address(&$1, $1.lexeme); gen_assignment(list, $1, $3); } ;loc : loc '[' boolean ']' { }| ID { address(&$$, $1.lexeme); };boolean : boolean OR M boolean { backpatch(list, $1.falselist, $3.instr);$$.truelist = merge($1.truelist, $4.truelist);$$.falselist = $4.falselist; }| boolean AND M boolean { backpatch(list, $1.truelist, $3.instr);$$.truelist = $4.truelist;$$.falselist = merge($1.falselist, $4.falselist); }| '!' boolean { $$.truelist = $1.falselist;$$.falselist = $1.truelist; }| '(' boolean ')' { $$.truelist = $1.truelist;$$.falselist = $1.falselist; }| expression REL expression { $$.truelist = new_instrlist(nextinstr(list));$$.falselist = new_instrlist(nextinstr(list)+1);gen_if(list, $1, $2.oper, $3);gen_goto_blank(list); }| TRUE { address(&$$, "TRUE");gen_goto_blank(list); }| FALSE { address(&$$, "FALSE");gen_goto_blank(list); }| expression { addr_node(&$$, $1); };M : { $$.instr = nextinstr(list); };N : { $$.nextlist = new_instrlist(nextinstr(list));gen_goto_blank(list); };expression : expression '+' expression { new_temp(&$$, get_temp_index(list)); gen_3addr(list, $$, $1, "+", $3); } | expression '-' expression { new_temp(&$$, get_temp_index(list)); gen_3addr(list, $$, $1, "-", $3); }| expression '*' expression { new_temp(&$$, get_temp_index(list)); gen_3addr(list, $$, $1, "*", $3); }| expression '/' expression { new_temp(&$$, get_temp_index(list)); gen_3addr(list, $$, $1, "/", $3); }| '-' expression %prec UMINUS { new_temp(&$$, get_temp_index(list)); gen_2addr(list, $$, "-", $2); }| loc { addr_node(&$$, $1); }| NUMBER { address(&$$, $1.lexeme); }| REAL { address(&$$, $1.lexeme); };%%#include"lex.yy.c"int yyerror(char* msg){printf("\nERROR with message: %s\n", msg);return 0;}int main(){list = newcodelist();yyparse();print(list);return 0;}2、Goto.c#ifndef GOTO_C#define GOTO_C#include <stdio.h>#include <string.h>#include <malloc.h>typedef struct listele{int instrno;struct listele *next;}listele;listele* new_listele(int no){listele* p = (listele*)malloc(sizeof(listele));p->instrno = no;p->next = NULL;return p;}typedef struct instrlist{listele *first,*last;}instrlist;instrlist* new_instrlist(int instrno){instrlist* p = (instrlist*)malloc(sizeof(instrlist));p->first = p->last = new_listele(instrno);return p;}instrlist* merge(instrlist *list1, instrlist *list2){instrlist *p;if (list1 == NULL) p = list2;else{if (list2!=NULL){if (list1->last == NULL){list1->first = list2->first;list1->last =list2->last;}else list1->last->next = list2->first;list2->first = list2->last = NULL;free(list2);}p = list1;}return p;}typedef struct node{instrlist *truelist, *falselist, *nextlist;char addr[256];char lexeme[256];char oper[3];int instr;}node;int op_in(node *dst, char *src){strcpy(dst->oper, src);return 0;}int lexeme_in(node *dst, char *yytext){strcpy(dst->lexeme, yytext);return 0;}int address(node *dst, char *src){strcpy(dst->addr, src);return 0;}int new_temp(node *dst, int index){sprintf(dst->addr, "t%d", index);return 0;}int addr_node(node *dst, node src){strcpy(dst->addr, src.addr);return 0;}typedef struct codelist{int linecnt, capacity;int temp_index;char **code;}codelist;codelist* newcodelist(){codelist* p = (codelist*)malloc(sizeof(codelist));p->linecnt = 0;p->capacity = 1024;p->temp_index = 0;p->code = (char**)malloc(sizeof(char*)*1024);return p;}int get_temp_index(codelist* dst){return dst->temp_index++;}int nextinstr(codelist *dst) { return dst->linecnt; }int Gen(codelist *dst, char *str){if (dst->linecnt >= dst->capacity){dst->capacity += 1024;dst->code = (char**)realloc(dst->code, sizeof(char*)*dst->capacity);if (dst->code == NULL){printf("Error!\n");return 0;}}dst->code[dst->linecnt] = (char*)malloc(strlen(str)+20);strcpy(dst->code[dst->linecnt], str);dst->linecnt++;return 0;}char tmp[1024];int gen_goto_blank(codelist *dst){sprintf(tmp, "goto");Gen(dst, tmp);return 0;}int gen_goto(codelist *dst, int instrno){sprintf(tmp, "goto L%d", instrno);Gen(dst, tmp);return 0;}int gen_if(codelist *dst, node left, char* op, node right){sprintf(tmp, "if %s %s %s goto", left.addr, op, right.addr);Gen(dst, tmp);return 0;}int gen_1addr(codelist *dst, node left, char* op){sprintf(tmp, "%s %s", left.addr, op);Gen(dst, tmp);return 0;}int gen_2addr(codelist *dst, node left, char* op, node right){sprintf(tmp, "%s = %s %s", left.addr, op, right.addr);Gen(dst, tmp);return 0;}int gen_3addr(codelist *dst, node left, node op1, char* op, node op2){sprintf(tmp, "%s = %s %s %s", left.addr, op1.addr, op, op2.addr);Gen(dst, tmp);return 0;}int gen_assignment(codelist *dst, node left, node right){gen_2addr(dst, left, "", right);return 0;}int backpatch(codelist *dst, instrlist *list, int instrno){if (list!=NULL){listele *p=list->first;char tmp[20];sprintf(tmp, " L%d", instrno);while (p!=NULL){if (p->instrno<dst->linecnt)strcat(dst->code[p->instrno], tmp);p=p->next;}}return 0;}int print(codelist* dst){int i;for (i=0; i < dst->linecnt; i++)printf("L%d: %s\n", i, dst->code[i]);return 0;}#endif六、实验结果1、输入程序2、输出结果七、实验心得本次实验要实现中间代码生成,也是本学期的最后一次实验,要在前4次实验的基础上完成,综合比较前4次实验,感觉本次实验难度挺高,首先,前4次实验的词法分析和语法分析需要有足够高的正确率,否者本次实验中会遇到一些神奇的问题,不知道错在哪里;其次,对语法制导定义和语法制导翻译要掌握好才能把握编写思路。
词法分析器实验报告引言:词法分析器(Lexical Analyzer)是编译器的重要组成部分,其主要任务是将源代码转化为一个个独立的词法单元,为语法分析器提供输入。
在本次实验中,我们设计并实现了一个简单的词法分析器,通过对其功能和性能的测试,评估其在不同场景下的表现。
实验目的:1. 确定词法分析器的输入和输出要求;2. 通过构建适当的正则表达式规则,匹配不同类型的词法单元;3. 实现一个高效的词法分析器,确保在处理大型源代码时性能不受影响;4. 对词法分析器的功能和性能进行测试和评估。
实验过程:1. 设计词法分析器的接口:1.1 确定输入:源代码字符串。
1.2 确定输出:词法单元流,每个词法单元包含类型和对应的字符串值。
2. 构建正则表达式规则:2.1 识别关键字:根据编程语言的关键字列表构建正则表达式规则,将关键字与标识符区分开。
2.2 识别标识符:一般由字母、下划线和数字组成,且以字母或下划线开头。
2.3 识别数字:整数和浮点数可以使用不同的规则来识别。
2.4 识别字符串:使用引号(单引号或双引号)包裹的字符序列。
2.5 识别特殊符号:各类操作符、括号、分号等特殊符号需要单独进行规则设计。
3. 实现词法分析器:3.1 读取源代码字符串:逐个字符读取源代码字符串,并根据正则表达式规则进行匹配。
3.2 保存词法单元:将匹配到的词法单元保存到一个词法单元流中。
3.3 返回词法单元流:将词法单元流返回给调用者。
4. 功能测试:4.1 编写测试用例:针对不同类型的词法单元编写测试用例,包括关键字、标识符、数字、字符串和特殊符号。
4.2 执行测试用例:将测试用例作为输入传递给词法分析器,并检查输出是否和预期一致。
4.3 处理错误情况:测试词法分析器对于错误输入的处理情况,如非法字符等。
5. 性能测试:5.1 构建大型源代码文件:生成包含大量代码行数的源代码文件。
5.2 执行词法分析:使用大型源代码文件作为输入,测试词法分析器的性能。
学年第学期《编译原理》实验报告学院(系):计算机科学与工程学院班级:11303070A学号:***********姓名:无名氏指导教师:保密式时间:2016 年7 月目录1.实验目的 (1)2.实验内容及要求 (1)3.实验方案设计 (1)3.1 编译系统原理介绍 (1)3.1.1 编译程序介绍 (2)3.1.2 对所写编译程序的源语言的描述 (2)3.2 词法分析程序的设计 (3)3.3 语法分析程序设计 (4)3.4 语义分析和中间代码生成程序的设计 (4)4. 结果及测试分析 (4)4.1软件运行环境及限制 (4)4.2测试数据说明 (5)4.3运行结果及功能说明 (5)5.总结及心得体会 (7)1.实验目的根据Sample语言或者自定义的某种语言,设计该语言的编译前端。
包括词法分析,语法分析、语义分析及中间代码生成部分。
2.实验内容及要求(1)词法分析器输入源程序,输出对应的token表,符号表和词法错误信息。
按规则拼单词,并转换成二元形式;滤掉空白符,跳过注释、换行符及一些无用的符号;进行行列计数,用于指出出错的行列号,并复制出错部分;列表打印源程序;发现并定位词法错误;(2)语法分析器输入token串,通过语法分析,寻找其中的语法错误。
要求能实现Sample 语言或自定义语言中几种最常见的、基本的语法单位的分析:算术表达式、布尔表达式、赋值语句、if语句、for语句、while语句、do while语句等。
(3)语义分析和中间代码生成输入token串,进行语义分析,修改符号表,寻找其中的语义错误,并生成中间代码。
要求能实现Sample语言或自定义语言中几种最常见的、基本的语法单位的分析:算术表达式、布尔表达式、赋值语句、if语句、for语句、while 语句、do while语句等。
实验要求:功能相对完善,有输入、输出描述,有测试数据,并介绍不足。
3.实验方案设计3.1 编译系统原理介绍编译器逐行扫描高级语言程序源程序,编译的过程如下:(1).词法分析识别关键字、字面量、标识符(变量名、数据名)、运算符、注释行(给人看的,一般不处理)、特殊符号(续行、语句结束、数组)等六类符号,分别归类等待处理。
《编译原理》课程设计报告SLR(1)分析的实现院计算机科学与技术业计算机科学与技术指导教师姓名2015年12月26日目录1.设计的目的与内容1.1课程设计的目的1.2设计内容1.3设计要求1.4理论基础 2算法的基本思想2.1主要功能函数2.2算法思想SLR文法构造分析表的主要思想: 解决冲突的方法:SLR语法分析表的构造方法:3主要功能模块流程图3.1主函数功能流程图 4系统测试5结论附录程序源码清单11121.设计的目的与内容1.1课程设计的目的编译原理课程设计是计算机专业重要的教学环节, 本上的理论知识和实际有机的结合起来,独立分析和解决实际问题的机会。
进一步巩固和复习编译原理的基础知识。
培养学生结构化程序、模块化程序设计的方法和能力。
提高学生对于编程语言原理的理解能力。
加深学生对于编程语言实现手段的印象。
1.2设计内容构造LR(1分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子, 了解LR( K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
1.3设计要求SLR(1分析表的生成可以选择编程序生成,也可选择手动生成;1.4理论基础由于大多数适用的程序设计语言的文法不能满足 量说明这样简单的文法也不一定是 LR(0)文法。
因此对于LR(O规范族中有冲突的项目集 (状态) 它为学生提供了一个既动手又动脑, 将课 2) 程序要求要配合适当的错误处理机制;3) 要打印句子的文法分析过程。
1) LR(0)文法的条件,即使是描述一个实数变用向前查看一个符号的办法进行处理,以解决冲突。
这种办法将能满足一些文法的需要,因为只对有冲突的状态才向前查看一个符号,以确定做那种动作,因而称这种分析方法为简单的LR(1 分析法,用SLR(1表示。
2算法的基本思想2. 1 主要功能函数class WFWF (char s1 [], char s2 [], int x ,int yWF (const string & s1 , const stri ng & s2 bool op erator < (con st WF & a ) con stbool op erator ==(con st WF & a ) con st void p ri nt () )int x , int y )};class Closurevoid p rint(string strbool op erator (con st Closure & a ) const};void make item ()void dfs (const stri ng & xvoid make first ()void append (con st stri ng & str1 , const stri ng & str2bool check (con st vector <int >& id , const string str void make_follow ()void make_set ()void make_V ()void make_cmp ( vector <WF>& cmp1void make_go ()void make_table ()void print (string s1 ,string s2 s6 , stri ng s7 )stri ng get_ste ps (int x )stri ng get_stk((vector <T> stk ) stri ng get_shift (WF& temp ),string s3 , stringint i , char ch )s4 , string s5 , stringvoid analyse ( string src )2.2算法思想SLR文法构造分析表的主要思想:许多冲突性的动作都可能通过考察有关非终结符的FOLLOW集而获解决。
词法分析器实验报告词法分析器实验报告一、引言词法分析器是编译器中的重要组成部分,它负责将源代码分解成一个个的词法单元,为之后的语法分析提供基础。
本实验旨在设计和实现一个简单的词法分析器,以深入理解其工作原理和实现过程。
二、实验目标本实验的目标是设计和实现一个能够对C语言代码进行词法分析的程序。
该程序能够将源代码分解成关键字、标识符、常量、运算符等各种词法单元,并输出其对应的词法类别。
三、实验方法1. 设计词法规则:根据C语言的词法规则,设计相应的正则表达式来描述各种词法单元的模式。
2. 实现词法分析器:利用编程语言(如Python)实现词法分析器,将源代码作为输入,根据词法规则将其分解成各种词法单元,并输出其类别。
3. 测试和调试:编写测试用例,对词法分析器进行测试和调试,确保其能够正确地识别和输出各种词法单元。
四、实验过程1. 设计词法规则:根据C语言的词法规则,我们需要设计正则表达式来描述各种词法单元的模式。
例如,关键字可以使用'|'操作符将所有关键字列举出来,标识符可以使用[a-zA-Z_][a-zA-Z0-9_]*的模式来匹配,常量可以使用[0-9]+的模式来匹配等等。
2. 实现词法分析器:我们选择使用Python来实现词法分析器。
首先,我们需要读取源代码文件,并将其按行分解。
然后,针对每一行的代码,我们使用正则表达式进行匹配,以识别各种词法单元。
最后,我们将识别出的词法单元输出到一个结果文件中。
3. 测试和调试:我们编写了一系列的测试用例,包括各种不同的C语言代码片段,以测试词法分析器的正确性和鲁棒性。
通过逐个测试用例的运行结果,我们可以发现和解决词法分析器中的问题,并进行相应的调试。
五、实验结果经过多次测试和调试,我们的词法分析器能够正确地将C语言代码分解成各种词法单元,并输出其对应的类别。
例如,对于输入的代码片段:```cint main() {int a = 10;printf("Hello, world!\n");return 0;}```我们的词法分析器将输出以下结果:```关键字:int标识符:main运算符:(运算符:)运算符:{关键字:int标识符:a运算符:=常量:10运算符:;标识符:printf运算符:(常量:"Hello, world!\n"运算符:)运算符:;关键字:return常量:0运算符:;```可以看到,词法分析器能够正确地将代码分解成各种词法单元,并输出其对应的类别。
一、实验目的1. 理解编译原理的基本概念和原理。
2. 掌握编译器的各个阶段及其实现方法。
3. 能够运用编译原理的知识解决实际问题。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 20194. 实验内容:词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成三、实验内容1. 词法分析(1)实验目的:实现一个简单的词法分析器,将源代码中的字符序列转换为词法符号序列。
(2)实验步骤:1)定义词法符号类型,包括标识符、关键字、运算符、常量等。
2)设计词法分析器算法,对源代码进行遍历,将字符序列转换为词法符号序列。
3)实现词法分析器程序,输出词法符号序列。
(3)实验结果:输入源代码:int a = 10;输出词法符号序列:{<int, int>, <a, a>, <=, =>, <10, 10>, <;, ;>}2. 语法分析(1)实验目的:实现一个简单的语法分析器,将词法符号序列转换为抽象语法树(AST)。
(2)实验步骤:1)定义语法规则,包括产生式、非终结符、终结符等。
2)设计语法分析算法,根据语法规则对词法符号序列进行解析,生成AST。
3)实现语法分析器程序,输出AST。
(3)实验结果:输入词法符号序列:{<int, int>, <a, a>, <=, =>, <10, 10>, <;, ;>}输出AST:```AST:- ExpressionStatement- Expression- BinaryExpression- Identifier: a- Operator: =- Constant: 10```3. 语义分析(1)实验目的:实现语义分析器,对AST进行语义检查,确保程序的正确性。
(2)实验步骤:1)定义语义规则,包括类型检查、作用域检查等。
编译原理实验报告词法分析器实验目的1.熟练掌握词法分析程序的基本原理2.掌握词法分析程序的设计和实现实验内容1.针对一个简化的C语言子集完成对它的词法分析程序的设计与实现2.C语言子集的单词符号挤内码值程序代码:#include "stdio.h"#include "string.h"int i,j,k;char s;char a[20],token[20];int letter(){if((s>=97)&&(s<=122))return 1;else return 0;}int digit(){if((s>=48)&&(s<=57))return 1;else return 0;}void get(){s=a[i];i=i+1;}void retract(){i=i-1;}int lookup(){if(strcmp(token, "while")==0)return 1;else if(strcmp(token, "if")==0)return 2;else if(strcmp(token,"else")==0)return 3;else if(strcmp(token,"switch")==0)return 4;else if(strcmp(token,"case")==0)return 5;else return 0;}void main(){printf("输入源程序,结束用'#':\n");i=0;do{i++;scanf("%c",&a[i]);}while(a[i]!='#');i=1;memset(token,0,sizeof(char)*20);j=0;get();while(s!='#'){if(s==' ')get();else{switch(s){case'a':case'b':case'c':case'd':case'e':case'f':case'g':case'h':case'i':case'j':case'k':case'l':case'm':case'n':case'o':case'p':case'q':case'r':case's':case't':case'u':case'v':case'w':case'x':case'y':case'z':while(letter(s)||digit(s)){token[j]=s;j++;get();}retract();k=lookup();if(k==0)printf("(%d,%s)\n",6,token); else printf("(%d,unll)\n",k); break;case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':while(digit(s)){token[j]=s;j=j+1;get();}retract();printf("(%d,%s)\n",7,token); break;case'+':printf("(+,null)\n"); break;case'-':printf("(-,null)\n");break;case'*':printf("(*,null)\n");break;case'<':get();if(s=='=')printf("(relop,LE)\n");else {retract();printf("(relop,LT)\n");}break;case'=':get();if(s=='=')printf("(relop,EQ)\n");else{retract();printf("(=,null)\n");}break;case';':printf("(;,null)\n");break;default:printf("(%c,error)\n",s);break;}memset(token,0,sizeof(char)*10);j=0;get();}}}运行结果:编译原理实验报告语法分析器实验目的1.熟练掌握语法分析程序的基本原理2.掌握用算符优先分析法来构造,设计优先函数3.掌握语法分析程序的设计与实现实验内容1.针对一个简单文法完成对它的语法分析程序的设计与实现2.通过语法分析程序来完成多输入的算数表达式进行计算并相应得到的对应四元式程序代码:#include <stdio.h>char a[20],optr[10],s,op;int i,j,k,opnd[10],x1,x2,x3;int operand(char s){if((s>='0')&&(s<='9'))return 1;elsereturn 0;}int f(char s){switch(s){case'+':return 6;case'-':return 8;case'*':return 10;case'/':return 12;case'(':return 2;case')':return 12;case'#':return 2;default:printf("error!\n");}}int g(char s){switch(s){case'+':return 5;case'-':return 7;case'*':return 9;case'/':return 11;case'(':return 13;case')':return 2;case'#':return 2;default:printf("error!\n");}}void get(){i=i+1;s=a[i];}void main(){printf("请输入算数表达式,以'#'结束:\n");i=0;do{i=i+1;scanf("%c",&a[i]);}while(a[i]!='#');i=0;j=0;k=0;optr[j]='#';get();while((optr[j] != '#')||(s != '#')){if(operand(s)){opnd[k]=s-'0';k=k+1;get();}else if(f(optr[j])>g(s)){op=optr[j];j=j-1;x2=opnd[k-1];x1=opnd[k-2];k=k-2;switch(op){case'+':x3=x1+x2;break;case'-':x3=x1-x2;break;case'*':x3=x1*x2;break;case'/':x3=x1/x2;break;}opnd[k]=x3;k=k+1;printf("(%c,%d,%d,%d)\n",op,x1,x2,x3);}else if(f(optr[j]) < g(s)){j=j+1;optr[j]=s;get();}else if(f(optr[j]) == g(s)){j=j-1;get();}elseprintf("error!");}}运行结果:。
编译原理实验报告题目C_minus语言词法分析器学院计算机科学与技术专业 XXXXXXXXXXXXXXXX 学号 XXXXXXXXXXXX 姓名 XXXX 指导教师 XXXX2xx年xx月xx日C minus语言词法分析器一、实验目的理解词法分析器的设计方法利用DFA编写相应的程序。
掌握手工编写词法分析程序的方法。
复习熟悉以前学过的编程语言通过实验了解编译器词法分析的工作原理二、实验原理文法的概念,DFA的表示方法。
词法分析程序的输出和输入词法分析程序的功能是读入源程序,输出单词符号。
单词符号是程序设计语言的比本语法符号,程序设计语言的单词符号一般分为如下几种关键字,标示符,常数,运算符,界符,单词的输出是二元式的形式,需要知道二元式的表示方法,把得到的二元式写入输出文件。
转化图如下熟悉单词的描述工具,如正规文法,正规式,以及知道正规文法和正规式的等价性以及他们之间的互相转化。
熟悉把正规文法转化为正规式,把正规式转化为NFA以及把NFA转为相应的DFA最后再把DFA简化,DFA的状态转化为相应的子程序,最后得到词法分析器状态最小DFA词法分析器匹规式<状态最小DFA词法分析器丿>DFA^^正规文法TC语言的基本语法。
三、实验要求1、该个词法分析器要求至少能够识别以下几类单词关键字else if int return void while 共6个,所有的关键字都是保留字,并且必须是小写;标识符识别与 C语言词法规定相一致的标识符,通过下列正则表达式定义TOC \o "1-5" \h \z ID=letter (letter | digit)* ;常数NUM=digit digit*(.digit digit* | & )(e(+ | - | &) digit digit* | & ),letter=a|..|z|A|..|Z| , digit=|..|9 ,包括整数,如 123 等;小数,如 1245 等;科学计数法表示的常数,如 23e3 , 3e-9等;专用符号+ - * / < <=> >===!==, ( )[]{ } ;2、分析器的输入为由上述几类单词构成的程序,输出为该段程序的机内表示形式,即关键字、运算符、界限符变为其对应的机内符,常数使用二进制形式,标识符使用相应的标识符表指针表示。
PL/0 语言编译器分析实验报告一、实验目的通过阅读与解析一个实际编译器(PL/0语言编译器)的源代码,加深对编译阶段(包括词法分析、语法分析、语义分析、中间代码生成等)和编译系统软件结构的理解,并达到提高学生学习兴趣的目的。
二、实验要求(1)要求掌握基本的程序设计技巧(C语言)和阅读较大规模程序源代码的能力;(2)理解并掌握编译过程的逻辑阶段及各逻辑阶段的功能;(3)要求能把握整个系统(PL/0语言编译器)的体系结构,各功能模块的功能,各模块之间的接口;(4)要求能总结出实现编译过程各逻辑阶段功能采用的具体算法与技术。
三、实验步骤(1) 根据PL/0语言的语法图,理解PL/0语言各级语法单位的结构,掌握PL/0语言合法程序的结构;(2)从总体上分析整个系统的体系结构、各功能模块的功能、各模块之间的调用关系、各模块之间的接口;(3)详细分析各子程序和函数的代码结构、程序流程、采用的主要算法及实现的功能;(4)撰写分析报告,主要内容包括系统结构框图、模块接口、主要算法、各模块程序流程图等。
四、报告内容pl/0语言是pascal语言的一个子集,我们这里分析的pl/0的编译程序包括了对pl/0语言源程序进行分析处理、编译生成类pcode代码,并在虚拟机上解释运行生成的类pcode代码的功能。
pl/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。
词法分析和代码生成作为独立的子程序供语法分析程序调用。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调用类pcode 解释程序解释执行生成的类pcode代码。
PL/0语言文法的EBNF表示EBNF表示的符号说明。
〈〉用左右尖括号括起来的中文字表示语法构造成分,或称语法单位,为非终结符。
∷=该符号的左部由右部定义,可读作“定义为”。
|表示“或”,为左部可由多个右部定义。
{ }花括号表示其内的语法成分可以重复。
在不加上下界时可重复0到任意次数,有上下界时为可重复次数的限制。
2016级《编译原理课程设计》总结报告(组)_2019_年_5_月_25_日第三部分词法分析源程序一般表现为字符串(机器语言称其为ASCII码)序列的形式,而编译程序的翻译工作应该在单词一级上进行,这与自然语言的翻译理解过程是类似的。
因此要进行编译工作,首先要把源程序的字符序列翻译成单词序列。
词法分析是编译过程的第一阶段。
它的任务就是对输入的字符串形式的源程序按顺序进行扫描,根据源程序的词法规则识别具有独立意义的单词(符号),并输出与其等价的TOKEN序列。
TOKEN是单词(符号)的部表示。
完成词法分析任务的程序称为词法分析程序,通常也称为词法分析器或扫描器(scanner)。
TOKEN是单词在编译程序处理过程中的一种部表示,也是词法分析程序对程序中各类单词进行处理之后的输出形式。
对于一种语言而言,如何对它的单词进行分类,每一类单词的TOKEN数据结构的形式如何,都没有固定的模式,可以随编译程序的不同而不同。
通常TOKEN的结构可以分成两部分,单词的语法信息和语义信息。
其中语法信息记录的是这个单词的种类,语义信息则记录着这个单词的具体信息。
这样,就能为以后的语法分析和语义分析处理单词做好准备。
SNL语法分析对每类单词的分析结果的TOKEN结构为三元组(词法信息、语义信息以及该单词在源程序中的行号)。
实现词法分析器的注意事项:1.保留字和标识符名字的区分2.复合单词的处理3.向前搜索及回退4.数字的转换5.输入时边界的处理6.注释的处理词法分析主要的类有DoToken、Data、Rule、TokenDoToken是最主要的类,它包括identifier标识符列表、INTC常量列表、isIdentifier()标识符自动机、isINTC()数字常量自动机。
Data类包括tokenShow显示token用StringBuffer、tokenShow2测试token用StringBuffer、token token列表、separator 分隔符列表等、以及LL(1)分析表,终极符,非终极符等。
编译原理实验报告实验名称:分析调试语义分析程序TEST抽象机模拟器完整程序保证能用!!!!!一、实验目的通过分析调试TEST语言的语义分析和中间代码生成程序,加深对语法制导翻译思想的理解,掌握将语法分析所识别的语法范畴变换为中间代码的语义翻译方法。
二、实验设计程序流程图extern int TESTScan(FILE *fin,FILE *fout);FILE *fin,*fout; //用于指定输入输出文件的指针int main(){char szFinName[300];char szFoutName[300];printf("请输入源程序文件名(包括路径):");scanf("%s",szFinName);printf("请输入词法分析输出文件名(包括路径):");scanf("%s",szFoutName);if( (fin = fopen(szFinName,"r")) == NULL){printf("\n打开词法分析输入文件出错!\n");return 0;}if( (fout = fopen(szFoutName,"w")) == NULL){printf("\n创建词法分析输出文件出错!\n");return 0;}int es = TESTScan(fin,fout);fclose(fin);fclose(fout);if(es > 0)printf("词法分析有错,编译停止!共有%d个错误!\n",es);else if(es == 0){printf("词法分析成功!\n");int es = 0;es = TESTparse(szFoutName); //调语法分析if(es== true) printf("语法分析成功!\n");else printf("语法分析错误!\n");}elseprintf("词法分析出现未知错误!\n");}Parse.cpp#include<stdio.h>#include<string.h>#include<ctype.h>#include<conio.h>#include<vector>// functionbool TESTparse();bool compound_Stat();bool program();bool statement();bool expression_stat();bool expression();bool bool_expr();bool additive_expr();bool term();bool factor();bool if_stat();bool while_stat();bool for_stat();bool write_stat();bool read_stat();bool declaration_stat();bool declaration_list();bool statement_list();bool compound_stat();char token[20],token1[40]; //token保存单词符号,token1保存单词值FILE *fp; //用于指向输入文件的指针int EsLine = 0;typedef struct{int es;int line;}EsInf;std::vector<EsInf> StackEs;//语法分析程序void ProcessError(int es){EsInf temp;temp.es = es;temp.line = EsLine;StackEs.push_back(temp);}bool Read *tok, char *tok1){if(feof(fp))return false;fscanf(fp,"%s\t%s\n",tok,tok1);printf("%s\t%s\n",tok,tok1);EsLine++;return true;}bool TESTparse(char *p){bool es = true;if((fp=fopen(p,"r"))==NULL){printf("\n打开%s错误!\n",p);return false;}elseprogram();if(!feof(fp))ProcessError(9);fclose(fp);printf("=====语法分析结果!=====\n");if(StackEs.size() == 0){printf("语法分析成功!\n");return true;}else{int i;for(i = 0; i < StackEs.size(); i++){printf("在第%d行",StackEs[i].line);switch(StackEs[i].es){case 1:printf("缺少{!\n");break;case 2:printf("缺少}!\n");break;case 3:printf("缺少标识符!\n");break;case 4:printf("缺少分号!\n");break;case 5:printf("缺少(!\n");break;case 6:printf("缺少)!\n");break;case 7:printf("缺少操作数!\n");break;case 8:printf("文件为空!\n");break;case 9:printf("文件尾有多余字符!\n");break;case 10:printf("\n打开%s错误!\n",p);break;}}return false;}}//《程序》::={<声明序列><语句序列>}//program::={<declaration_;list><statement_list>}bool program(){bool es = true;if( Read) == false ){ProcessError(8); // 文件结束return false;}if(strcmp(token,"{")) //判断是否为‘{’ProcessError(1);if( Read) == false ) // 文件中仅有{ProcessError(2);es = declaration_list();if(es == false)return false;es = statement_list();if(es == false)return false;if(strcmp(token,"}")) //判断是否为‘}’ProcessError(2);return true;}//<声明序列>::=<声明序列><声明语句>|<声明语句>//<declaration>::=//<declaration_list><declaration_stat>|ε//改成<declaration_list>::={<declaration_stat>}bool declaration_list(){bool es = true;while (strcmp(token,"int")==0){es = declaration_stat();if(es == false)return false;}return es;}//<声明语句>::=int<变量>;//<declaration_stat>::=int ID;bool declaration_stat(){bool es = true;if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token,"ID"))ProcessError(3); //不是标识符if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token,";"))ProcessError(4);if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}return(es);}//<语句序列>::=<语句序列><语句>|ε//<statement_list>::=<statement_list><statement>|ε//改成<statement_list>::={<statement>}bool statement_list(){bool es = true;if(feof(fp))return false;while(strcmp(token,"}")){es = statement();if(es == false)return(es);}return(es);}//<语句>::=<if语句>|<while语句>|<for语句>|<read语句>// |<write语句>|<复合语句>|<表达式语句>//<statement>::=<if_sttat>|<while_stat>|<for_stat>// |<compound_stat>|<expression_stat>bool statement(){bool es = true;if(strcmp(token,"if")==0 )es=if_stat(); //<if语句>else if(strcmp(token,"while")==0 )es=while_stat(); //<while语句>else if(strcmp(token,"for")==0 )es=for_stat(); //<for语句>else if(strcmp(token,"read")==0 )es=read_stat(); //<read语句>else if(strcmp(token,"write")==0 )es=write_stat(); //<write语句>else if(strcmp(token,"{")==0 )es=compound_stat(); //<复合语句>else if(strcmp(token,"ID")==0 || strcmp(token,"NUM")==0 || strcmp(token,"(")==0 ) es=expression_stat(); //<表达式语句>return(es);}//<if语句>::=if(<表达式>)<语句>[else<语句>]//<if_stat>::=if(<expressiion>)<statement>[else<statement>] bool if_stat(){bool es = true; //ifif( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token,"("))ProcessError(5); //少左括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es = expression();if(es == false)return(es);if(strcmp(token,")"))ProcessError(6); //少右括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=statement();if(es == false)return(es);if(strcmp(token,"else")==0) //else部分处理{if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=statement();if(es == false)return(es);}return(es);}//<while语句>::=while(<表达式>)<语句>//<while_stat>::=while<espr><statement>bool while_stat(){bool es = true;if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token,"("))ProcessError(5); //少左括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es = expression();if(es == false)return(es);if(strcmp(token,")"))ProcessError(6); //少右括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es = statement();if(es == false)return es;return(es);}//<for语句>::=for(<表达式>;<表达式>;<表达式>)<语句>//<for_stat>::=for(<expression>;<expression>;<expression>)<statement> bool for_stat(){bool es = true;if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token,"(")) ProcessError(5); //少左括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=expression();if(es == false) return (es);if(strcmp(token,";")) ProcessError(4); //少分号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=expression();if(es == false) return (es);if(strcmp(token,";")) ProcessError(4); //少分号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=expression();if(es == false) return (es);if(strcmp(token,")")) ProcessError(6); //少右括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=statement();if(es == false) return (es);return es;}//<write_语句>::=write<表达式>;//<write_stat>::=write<expression>bool write_stat(){bool es = true;if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=expression();if(es == false) return (es);if(strcmp(token,";")) ProcessError(4); //少分号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}return es;}//<read_语句>::=read<变量>//<read_stat>::=read Id;bool read_stat(){bool es = true;if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token,"ID")) ProcessError(3); //少标识符if(strcmp(token,";")) ProcessError(4); //少分号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}return es;}//<复合语句>::{<语句序列>}//<compound_stat>::={<statement_list>}bool compound_stat() //复合语句函数{bool es = true;if( Read) == false )ProcessError(2); // 缺少}return false; // 文件结束}es = statement_list();if(es == false)return es;// -------------- new----------if(strcmp(token1,"}") != 0)ProcessError(2);else{if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}}// --------------- new ----------return es;}//<表达式语句>::=<<表达式>;|;//<expression_stat>::=<expression>;|;bool expression_stat(){bool es = true;if(strcmp(token,";")==0){if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}return es;es=expression();if(es == false) return es;if(strcmp(token,";")==0){if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}return es;}else{ProcessError(4); //少分号}return es;}//<表达式>::=<标识符>=<布尔表达式>|<布尔表达式>//<expression>::=ID=<bool_expr>|<bool_expr>bool expression(){bool es = true;int ;char token2[20],token3[40];if(strcmp(token,"ID")==0){(fp); //记住当前文件位置if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}if(strcmp(token2,"=")==0) //'='{if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=bool_expr();if(es == false) return es;}else{fseek(fp,); //若非‘=’,则文件指针回到‘=’前的标识符EsLine--;es=bool_expr();if(es == false) return es;}}else{es=bool_expr();if(es == false) return es;}return es;}//<布尔表达式>::= <算术表达式>[(>|<|>=|<=|==|!=)<算数表达式>]//<bool_expr>::= <additive_expr> [(>|<|>=|<=|==|!=)<additive_expr>]bool bool_expr(){bool es = true;es=additive_expr();if(es == false) return es;if(strcmp(token,">")==0||strcmp(token,">=")==0||strcmp(token,"<")==0||strcmp(token,"<=")==0||strcmp(token,"!=")==0||strcmp(token,"==")==0){if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=additive_expr();if(es == false) return es;}return es;}//<算数表达式>::=<项>{(+|-)<项>}//<additive_expr>::=<term>{(+|-)<term>}bool additive_expr(){bool es = true;es=term();if(es == false) return es;while(strcmp(token,"+")==0||strcmp(token,"-")==0) {if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=term();if(es== false) return es;}return es;}//<项>::=<因子>{(*|/)<因子>}//<term>::=<factor>{(*|/)<factor>}bool term(){bool es = true;es=factor();if(es == false) return es;while(strcmp(token,"*")==0||strcmp(token,"/")==0){if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=factor();if(es == false) return es;}return es;}//<因子>::=(<表达式>)|<标识符>|<无符号整数>//<factor>::=(<expression>)|ID|NUMbool factor(){bool es = true;if(strcmp(token,"(")==0){if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}es=expression();if(es==false) return es;if(strcmp(token,")")) ProcessError(6); //少右括号if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}}else{if(strcmp(token,"ID")==0||strcmp(token,"NUM")==0){if( Read) == false ){ProcessError(2); // 缺少}return false; // 文件结束}return es;}else{ProcessError(7); //缺少操作数}}return es;}Scan.cpp#include<ctype.h>#include<cstring>#include<stdio.h>// 保留字#define KEYWORDNUM 8char *pKeyword[KEYWORDNUM] = {"if", "else", "for", "while", "do", "int", "read", "write"};// 单分界符char szSingleWord[50] = "+-(){};,:";// 双分界符char szDoubleWord[10] = "<>!";// 其他符char *szDivide = "/";char *szStar = "*";char *szEqual = "=";#define STATUSNUM 16 //状态个数#define DATANUM 10 // 数据流个数// 数据流类型typedef unsigned int DATA;#define OTHER 0 // wrong input#define LETTER 1 // 字母#define DIGIT 2 // 数字#define SINGLEWORD 3 // 单分界符#define DOUBLEWORD 4 // 双分界符#define DIVIDE 5 // /#define EQUAL 6 // =#define STAR 7 // *#define SPACE 8 // 空白#define 9// 状态类型typedef unsigned int STA TUS;#define NOSTATUS 0 // wrong input#define START 1#define CASE_ID 2#define END_ID 3#define CASE_NUM 4#define END_NUM 5#define CASE_SINGLE 6#define END_SINGLE 7#define CASE_DOUBLE 8#define CASE_DOUBLE2 9#define END_DOUBLE 10#define CASE_DIVIDE 11#define CASE_NOTE 12#define END_NOTE 13#define CASE_ERROR 14#define END_ERROR 15// 状态转换表// :到达终结状态的数据不保存在输出串中int reflect[STATUSNUM][DA TANUM] ={ //OTHER LETTER DIGIT SINGLEWORDDOUBLEWORD DIVIDE EQUAL STAR SPACE/*NOSTATUS*/ {NOSTATUS, NOSTA TUS, NOSTATUS, NOSTA TUS, NOSTATUS, NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS},/*START*/ {CASE_ERROR,CASE_ID, CASE_NUM,CASE_SINGLE,CASE_DOUBLE,CASE_DIVIDE,CASE_DOUBLE,CASE_SINGLE,STA RT, START},/*CADE_ID*/ {END_ID, CASE_ID, CASE_ID, END_ID, END_ID, END_ID, END_ID, END_ID, END_ID, END_ID},/*END_ID*/ {NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTATUS, NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS},/*CASE_NUM*/ {END_NUM, END_NUM, CASE_NUM, END_NUM, END_NUM, END_NUM, END_NUM, END_NUM, END_NUM, END_NUM},/*END_NUM*/ {NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS,NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS}, /*CASE_SINGLE*/ {END_SINGLE,END_SINGLE, END_SINGLE, END_SINGLE, END_SINGLE, END_SINGLE, END_SINGLE, END_SINGLE,END_SINGLE, END_SINGLE},/*END_SINGLE*/ {NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTATUS, NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS},/*CASE_DOUBLE*/ {END_SINGLE,END_SINGLE, END_SINGLE,END_SINGLE, END_SINGLE, END_SINGLE,CASE_DOUBLE2,END_SINGLE,END_SINGLE, END_SINGLE},/*CASE_DOUBLE2*/{END_DOUBLE,END_DOUBLE, END_DOUBLE,END_DOUBLE, END_DOUBLE, END_DOUBLE, END_DOUBLE,END_DOUBLE, END_DOUBLE, END_DOUBLE},/*END_DOUBLE*/ {NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS},/*CASE_DIVIDE*/ {END_SINGLE,END_SINGLE, END_SINGLE,END_SINGLE, END_SINGLE, END_SINGLE, END_SINGLE,CASE_NOTE, E ND_SINGLE, END_SINGLE},/*CASE_NOTE*/ {END_NOTE, E ND_NOTE, END_NOTE, END_NOTE, END_NOTE, END_NOTE, END_NOTE, END_NOTE, END_NOTE, END_NOTE},/*END_NOTE*/ {NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTATUS, NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS},/*CASE_ERROR*/ {END_ERROR, END_ERROR, END_ERROR,END_ERROR, END_ERROR, END_ERROR, END_ERROR,END_ERROR, END_ERROR, END_ERROR},/*END_ERROR*/ {NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTATUS, NOSTATUS, NOSTA TUS, NOSTA TUS, NOSTA TUS, NOSTA TUS}};// 若在pString中找到word 则返回true,否则,返回falsebool SearchChar(char word,const char *pString){int n = strlen(pString);for(int i = 0; i < n; i++){if( word == pString[i])return true;}return false;}// 得到word的数据流类型DA TA GetDataByword(char word){if(word == EOF)return ;if(isalpha(word))return LETTER;if(isdigit(word))return DIGIT;if(SearchChar(word,szSingleWord))return SINGLEWORD;if(SearchChar(word,szDoubleWord))return DOUBLEWORD;if(SearchChar(word,szDivide))return DIVIDE;if(SearchChar(word,szEqual))return EQUAL;if(SearchChar(word,szStar))return STAR;if(isspace(word))return SPACE;return OTHER;}// 得到从status状态输入word后到达的状态STA TUS GetNextStatus(STATUS status, DA TA word){return reflect[status][word];}// 返回值表示错误个数。
实验名称:文法分析实验实验日期:2023年4月10日实验地点:计算机实验室实验目的:1. 理解文法分析的基本概念和原理。
2. 掌握使用文法分析工具进行语法分析的方法。
3. 分析给定文本的语法结构,提高对自然语言处理的认知。
实验器材:1. 计算机2. 文法分析工具(如:LL(1)分析器、LR(1)分析器等)3. 实验教材和参考资料实验步骤:一、文法分析基本概念介绍1. 定义文法:文法是描述一组字符串集合的规则,用于判断一个字符串是否属于该集合。
2. 语法分析:语法分析是自然语言处理中的一项基本任务,旨在将自然语言文本转换为结构化表示,如抽象语法树(AST)。
3. 文法分类:根据文法生成的方法,文法可以分为正规文法和上下文无关文法。
二、文法分析工具使用1. LL(1)分析器:LL(1)分析器是一种自底向上的分析器,适用于分析上下文无关文法。
其特点是易于实现,但只能处理部分上下文无关文法。
2. LR(1)分析器:LR(1)分析器是一种自底向上的分析器,适用于分析上下文无关文法。
其特点是能够处理更广泛的上下文无关文法,但实现相对复杂。
三、实验内容1. 分析给定文本的语法结构,提取出其文法规则。
2. 使用文法分析工具对文本进行语法分析,生成抽象语法树(AST)。
实验过程:一、文法规则提取以英文句子“Hello, how are you?”为例,其文法规则如下:S → NP VPNP → Det NVP → V NPDet → 'a' | 'an' | 'the'N → 'Hello' | 'how' | 'are' | 'you'V → 'are'二、文法分析工具使用1. 使用LL(1)分析器对句子进行语法分析:输入:Hello, how are you?输出:S -> NP VPNP -> Det NVP -> V NPDet -> 'the'N -> 'Hello'V -> 'are'NP -> Det NVP -> V NPDet -> 'how'N -> 'are'V -> 'you'2. 使用LR(1)分析器对句子进行语法分析:输入:Hello, how are you?输出:S -> NP VPNP -> Det NVP -> V NPDet -> 'the'N -> 'Hello'V -> 'are'NP -> Det NVP -> V NPDet -> 'how'N -> 'you'实验结果分析:通过使用文法分析工具对给定文本进行语法分析,我们可以清晰地看到文本的语法结构。
语法分析器的设计实验报告 一、实验内容 语法分析程序用LL(1)语法分析方法。首先输入定义好的文法书写文件(所用的文 法可以用LL(1)分析),先求出所输入的文法的每个非终结符是否能推出空, 再分 别计算非终结符号的FIRST集合,每个非终结符号的FOLLOW集合,以及每个 规则的SELECT集合,并判断任意一个非终结符号的任意两个规则的 SELECT 集的交集是不是都为空,如果是,则输入文法符合 LL(1)文法,可以进行分析。 对于文法: G[E]: E->E+T|T T->T*F|F F->i|(E) 分析句子i+i*i是否符合文法。
二、基本思想 1、语法分析器实现 语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,从由词 法分析输出的源程序符号串中识别出各类语法成分, 同时进行词法检查,为语义 分析和代码生成作准备。这里采用自顶向下的 LL(1)分析方法。
该程序可分为如下几步: (1) 读入文法 (2) 判断正误 (3) 若无误,判断是否为LL(1)文法 (4) 若是,构造分析表; (5) 由句型判别算法判断输入符号串是为该文法的句型。 三、核心思想 该分析程序有15部分组成: (1)首先定义各种需要用到的常量和变量; (2)判断一个字符是否在指定字符串中; (3)读入一个文法; (4)将单个符号或符号串并入另一符号串; (5)求所有能直接推出 & 的符号; (6)求某一符号能否推出‘ & '; (7)判断读入的文法是否正确; (8)求单个符号的 FIRST; (9)求各产生式右部的 FIRST; (10)求各产生式左部的 FOLLOW ; (11)判断读入文法是否为一个 LL(1) 文法; (12)构造分析表 M ; (13)句型判别算法; (14)一个用户调用函数; (15)主函数; 下面是其中几部分程序段的算法思想: 1、求能推出空的非终结符集 I、实例中求直接推出空的 empty集的算法描述如下:
void emp(char c){ 参数 c 为空符号
char temp[10]; 定义临时数组 int i;
for(i=0;i<=count-1;i++) 从文法的第一个产生式开始查找 { if 产生式右部第一个符号是空符号并且右部长度为 1, then 将该条产生式左部符号保存在临
时数组 temp 中 将临时数组中的元素合并到记录可推出 & 符号的数组 empty 中。 } U、求某一符号能否推出&
int _emp(char c) { //若能推出 & ,返回 1;否则,返回 0
int i,j,k,result=1,mark=0; char temp[20];
temp[0]=c; temp[1]='\0'; 存放到一个临时数组 empt 里,标识此字符已查找其是否可推出空字 如果c在可直接推出空字的 empty[]中,返回1 for(i=0;;i++) { if(i==count)
return(0);
找一个左部为 c 的产生式 j=strlen(right[i]); //j 为 c 所在产生式右部的长度 if右部长度为1且右部第一个字符在 empty[]中.then返回1(A->B,B可推出空) if 右部长度为 1 但第一个字符为终结符 ,then 返回 0(A->a,a 为终结符 ) else{ for(k=0;k<=j-1;k++) { 查找临时数组 empt[]. 并标记 mark-=1(A->AB)
if 找到的字符与当前字符相同 (A->AB)
结束本次循环 else(mark 等于 0) 查找右部符号是否可推出空字 ,把返回值赋给 result 把当前符号加入到临时数组 empt[] 里. } if 当前字符不能推出空字且还没搜索完全部的产生式 then 跳出本次循环继续搜索
下一条产生式 else if //当前字符可推出空字 ,返回 1 }
} }
2、计算每个符号的 first 集: 实例中求单个符号的 FIRST 集的算法描述如下: void first2 (int i) { 参数 i 为符号在所有输入符号中的序号 c 等于指示器 i 所指向的符号 在保存终结符元素的 termin[] 数组查找 c if c 为终结符(c€ VT ), then FIRST(c)={c} 在保存终结符元素的 non_ter[] 数组查找 c if c是非终结符(c € VN ) 在所有产生式中查找 c 所在的产生式 if 产生式右部第一个字符为终结符或空 (即cTa (a€ VT)或c^ &) then 把a或&加进FIRST(c) if 产生式右部第一个字符为非终结符 then if 产生式右部的第一个符号等于当前字符 then 跳到下一条产生式进行查找 求当前非终结符在所有字符集中的位置 if 当前非终结符还没求其 FIRST 集 then 查找它的 FIRST 集并标识此符号已求其 FIRST 集 求得结果并入到 c 的 FIRST 集. if 当前产生式右部符号可推出空字且当前字符不是右部的最后一个字符 then 获取右部符号下一个字符在所有字符集中的位置 if 此字符的 FIRST 集还未查找 then 找其 FIRST 集,并标其查找状态为 1 把求得的FIRST集并入到c的FIRST集. if 当前右部符号串可推出空且是右部符号串的最后一个字符 (即产生式为 ct Y1Y2…Yk,若对一切 1<=i<=k,均有 & € FIRST(Y i),则将& €符号加进 FIRST(c)) the n 把空字加入到当前字符 c的FIRST集.
else 不能推出空字则结束循环 标识当前字符c已查找其FIRST集.}
3. 计算 FOLLOW FOLLOW集的构造可用如下方法来求: 对于文法中的符号 X • VN ,其FOLLOW(A)集合可反复应用下列规则计算,直到 FOLLOW(A)集合不再增大为止。 (1) 对于文法开始符号 S,因为S S,故# FOLLOW(S); (2) 若 Ar B 一:,其中 B VN^.三(VT VN)*、“(VT VN)+,贝V FIRST( -)-{ } FOLLOW(B); (3) 若 AT :• B 或 AT :• B 1 (「丄• 3,贝U FOLLOW(A) FOLLOW(B)。 FOLLOW集的算法描述如下: void FOLLOW(i nt i) X为待求的非终结符
把当前字符放到一临时数组 fo叩中,标识求已求其FOLLOW集.避免循环递归 if X 为开始符号 then # € FOLLOW(X) 对全部的产生式找一个右部含有当前字符 X的产生式 注:比如求 FOLLOW(B)则找AT a X或AT X £
)的产生式
if X在产生式右部的最后(形如产生式AT : X) then 查找非终结符A是否已经求过其 FOLLOW集.避免循环递归 if 非终结符 A已求过其 FOLLOW集 then FOLLOW(A) € FOLLOW(X) 继续查下一条产生式是否含有 X else 求A之FOLLOW 集,并标识为 A已求其FOLLOW 集
else if X不在产生式右部的最后(形如AT.^B :) then if右部X后面的符号串[能推出空字;then 查找P是否已经求过其 FOLLOW集.避免循环递归 if 已求过[的FOLLOW 集then
FOLLOW(A) € FOLLOW(B) 结束本次循环 else if :不能推出空字 then 求 FIRST(-) 把FIRST( 1)中所有非空元素加入到 FOLLOW(B)中 标识当前要求的非终结符 X的FOLLOW集已求过
4. 计算 SELECT! SELECT集的构造算法如下: 对所有的规则产生式 ATx : (1)若 x 不能推出空字 ,贝y SELECT(A Tx) = FIRST(x); ⑵若 x 可推出空字 ,贝y SELECT(A Tx)=FIRST(x) - { } FOLLOW(A)。 算法描述如下: for(i=0;i<=产生式总数-1;i++) 先把当前产生式右部的 FIRST集(一切非空元素,不包括&放入到当前产生式的 SELECT(i); if 产生式右部符号串可推出空字 ;then 把i指向的当前产生式左部的非终结符号的 FOLLOW集并入到SELECT(i)中
5. 判断是否LL(1)文法 要判断是否为LL(1)文法,需要输入的文法 G有如下要求: 具有相同左部的规则的 SELECT集两两不相交,即: SELECT(A T : ) ASELECT(A T 1)=. 如果输入的文法都符合以上的要求,则该文法可以用 LL(1)方法分析。 算法描述如下: 把第一条产生式的 SELECT(0)集放到一个临时数组 temp[]中 for(i=1;i<=产生式总数-1;i++) 求temp的长度length if i指向的当前产生式的左部等于上一条产生式的左部 then 把SELECT(i)并入到temp数组中 If temp的长度小于length加上SELECT (i)的长度 返回0 else 把temp清空 把SELECT (i)存放到temp中 结果返回1; 四、算法 #in clude #in clude #in clude
char first[50][50],follow[50][50]; 〃各产生式右部的 FIRST 和左部的 FOLLOW 集合 char first1[50][50]; char select[50][50]; II所有单个符号的FIRST集合
//各个产生式的 SELECT集合 char firstflag[50],followflag[50]; //记录各符号的 FIRST 和 FOLLOW 是否已求过 char empty[20]; //记录可推出&的符号
int coun t=0; int nu mber; char start; char term in[ 50]; char non _ter[50]; char v[50]; char left[50]; char right[50][50];
//产生式的个数 //所有终结符和非终结符的总数 〃开始符号 //终结符号 //非终结符号 //所有符号 //左部 〃右部
***************************************