编译原理最后的单人实验。
学校:烟大
老师是孔老师,孔老师是位十分认真负责的老师,跟着孔老师学了半年感觉学到了很多东西,感谢孔老师。
题目如上:扩展试验_语法制导翻译_2_B_2.将表达式翻译为后缀式-LR分析
本题扩展了乘法,括号的后缀转换,由于加法和减法,乘法和除法运算逻辑相同,所以只需实现加法,乘法,括号运算。
后面会贴上自己源码的下载链接:
词法分析部分由lex实现,语法分析手动构造的。
本实验代码参考了老师给的计算器calc.lex范例程序,和16级学长的实现方法,在此鸣谢。
源码分享:https://download.csdn.net/my/uploads 编译原理-2019压缩包正在审核。
百度云:链接:https://pan.baidu.com/s/1DZdJzZO4gCbaHyCZlxXxHw
提取码:o2vq
lex:
%option noyywrap
%{
#include <stdio.h>
#include <stdlib.h>
int num=0;
int num_num = 0;
int num_op = 0;
int aa[200]={0};
char cc[200]={0};
%}
INTEGER [1-9][0-9]*
ID [a-zA-Z][a-zA-Z]*
operate [+-*()]
SPACE [ \n\t]
over [#]
%%
{over} {
return 0;
}
{operate} {
cc[num]=*yytext;
num++;
}
{INTEGER} {
aa[num_num]=atoi(yytext);
cc[num]='i';
num++;
num_num++;
/*数字数加一*/
}
{SPACE} {
/*什么也不做,滤掉白字符和其它字符*/
}
. {
printf("error\n");
}
%%
int www()
{
yylex();
return 0;
}
LR分析部分:
LR.c文件:
#include<stdio.h>
#include<string.h>
#include"lex.h"
char *action[12][6]={"S5#",NULL,NULL,"S4#",NULL,NULL, /*ACTION表*/
NULL,"S6#",NULL,NULL,NULL,"acc",
"R2#","R2#","S7#","R2#","R2#","R2#",
"R4#","R4#","R4#","R4#","R4#","R4#",
"S5#",NULL,NULL,"S4#",NULL,NULL,
"R6#","R6#","R6#","R6#","R6#","R6#",
"S5#",NULL,NULL,"S4#",NULL,NULL,
"S5#",NULL,NULL,"S4#",NULL,NULL,
NULL,"S6#",NULL,NULL,"S11#",NULL,
"R1#","R1#","S7#","R1#","R1#","R1#",
"R3#","R3#","R3#","R3#","R3#","R3#",
"R5#","R5#","R5#","R5#","R5#","R5#"};
int goto1[12][3]={1,2,3, /*GOTO表*/
0,0,0,
0,0,0,
0,8,0,
8,2,3,
0,0,0,
0,9,3,
0,0,10,
0,0,0,
0,0,0,
0,0,0,
0,0,0};
char vt[6]={'i','+','*','(',')','#'}; /*存放非终结符*/
char vn[3]={'E','T','F'}; /*存放终结符*/
char *LR[7]={"L-E#","E-E+T#","E-T#","T-T*F#","T-F#","F-(E)#","F-i#"}; /*存放产生式*/
int a[20]; /*状态栈*/
char b[20],c[20],c1; /*符号栈, 剩余符号栈*/
int top1,top2,top3,top,m,n;
/*运行*/
void main(){
int g,h,i,j,k,l,p,y,z,count,dd=0;
char x,copy[10],copy1[10];
int top4=0;
char id[20];
top1=0; //状态栈栈顶
top2=0; //符号栈栈顶
top3=0; //指向最后一个符号串,记录输入符号的个数
top=0; //top指向输入栈栈顶
a[0]=0; //状态栈
y=a[0];
b[0]='#'; //符号栈
count=0;z=0;
printf("请输入表达式\n");
www();
cc[num]='#';
do{
y=z; /*y,z指向状态栈栈顶*/
m=0;
n=0;
g=top; //top指向输入栈栈顶
j=0;
k=0;
x=cc[top];
while(x!=vt[j]&&j<=5) j++; //判断当前符号是否是终结符
if(j==5&&x!=vt[j]){
printf("error\n");
return;
}
if(action[y][j]==NULL){ /*查表*/
printf("error\n");
return;
}
else
strcpy(copy,action[y][j]);
if(copy[0]=='S')
{ /*处理移进*/
i=1;
h=copy[i]-'0'; //计算下一个状态
i++;
while(copy[i]>='0'&©[i]<='9')
{
h=copy[i]-'0';
i++;
}
i=i-1;
z=copy[1]-'0';
for(j=2;j<=i;j++)
{
z=z*10+copy[j]-'0';
}
top1=top1+1;
top2=top2+1;
a[top1]=z; //将下一个状态数移进状态栈
b[top2]=x; //将读到的这个字符移进符号栈
top=top+1;
}
if(copy[0]=='R'){ /*处理归约*/
h=copy[1]-'0'; //H记录的是归约用到的产生式
if(h==6)
{
printf("%d ",aa[dd]);
dd++;
}
if(h==3)
{
printf("* ");
}
if(h==1)
{
printf("+ ");
}
strcpy(copy1,LR[h]); //copy1记录当前归约用到的产生式
while(copy1[0]!=vn[k]) k++; //k记录归约后产生的非终结符的位置
l=strlen(LR[h])-4;
//top1=top1-l+1;
//top2=top2-l+1;
top1=top1-l;
top2=top2-l;
y=a[top1-1]; //记录当前状态的上一个状态
p=goto1[y][k]; //下一个要跳转的状态
a[top1]=p;
b[top2]=copy1[0];
z=p;
}
}while(action[y][j]!="acc");
printf("\nacc\n");
for(i=0;i<top4;i++)
printf("%c ",id[i]);
printf("\n");
}
lex.h文件
/* A lexical scanner generated by flex */
/*LEX头文件*/
/* Scanner skeleton version:
* $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.85 95/04/24 10:48:47 vern Exp $
*/
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#include <stdio.h>
/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
#ifdef c_plusplus
#ifndef __cplusplus
#define __cplusplus
#endif
#endif
#ifdef __cplusplus
#include <stdlib.h>
#include <unistd.h>
/* Use prototypes in function declarations. */
#define YY_USE_PROTOS
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
#else /* ! __cplusplus */
#if __STDC__
#define YY_USE_PROTOS
#define YY_USE_CONST
#endif /* __STDC__ */
#endif /* ! __cplusplus */
#ifdef __TURBOC__
#pragma warn -rch
#pragma warn -use
#include <io.h>
#include <stdlib.h>
#define YY_USE_CONST
#define YY_USE_PROTOS
#endif
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
#ifdef YY_USE_PROTOS
#define YY_PROTO(proto) proto
#else
#define YY_PROTO(proto) ()
#endif
/* Returned upon end-of-file. */
#define YY_NULL 0
/* Promotes a possibly negative, possibly signed char to an unsigned
* integer for use as an array index. If the signed char is negative,
* we want to instead treat it as an 8-bit unsigned char, hence the
* double cast.
*/
#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
/* Enter a start condition. This macro really ought to take a parameter,
* but we do it the disgusting crufty way forced on us by the ()-less
* definition of BEGIN.
*/
#define BEGIN yy_start = 1 + 2 *
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
#define YY_START ((yy_start - 1) / 2)
#define YYSTATE YY_START
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
/* Special action meaning "start processing a new file". */
#define YY_NEW_FILE yyrestart( yyin )
#define YY_END_OF_BUFFER_CHAR 0
/* Size of default input buffer. */
#define YY_BUF_SIZE 16384
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern int yyleng;
extern FILE *yyin, *yyout;
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
/* The funky do-while in the following #define is used to turn the definition
* int a single C statement (which needs a semi-colon terminator). This
* avoids problems with code like:
*
* if ( condition_holds )
* yyless( 5 );
* else
* do_something_else();
*
* Prior to using the do-while the compiler would get upset at the
* "else" because it interpreted the "if" statement as being all
* done when it reached the ';' after the yyless() call.
*/
/* Return all but the first 'n' matched characters back to the input stream. */
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
*yy_cp = yy_hold_char; \
yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
YY_DO_BEFORE_ACTION; /* set up yytext again */ \
} \
while ( 0 )
#define unput(c) yyunp