当前位置:首页 » 编程软件 » 编译原理英语句子画图分析

编译原理英语句子画图分析

发布时间: 2022-09-13 14:36:13

编译原理

4、文法G为:
A->aABe/Ba
B->dB/ε
构造LL(1)分析表并判断adae是否是该文法的句子。
5、文法G为:
A->i:=E;
E->E+E
E->E*E
E->i
构造SLR分析表,并判断i:=i*i是否是该文法的句子。
6、文法G为:
S->E
E->aB/bB
A->cA/d
B->Cb/d
构造该文法的LR(0)和SLR(1)分析表,并模拟分析句子bcd时分析栈和输入串的变化。
7、文法G为:
E->E+T/T
T->T*F/F
F->P^F/P
P->(E)/i
判断该文法是否为算符优先文法,若是,构造优先表。

❷ 编译原理,如何判断一个FA是DFA还是NFA

DFA或NFA是对计算机程序的行为的抽象模型.你编写的程序其实就对应了一个自动机.简单举例来说,如果a,b可以取值0或1; 程序:if(a==1) b=1; 这个程序对应了一个自动机.
对应的自动机就有状态 (0,0),(0,1),(1,1),(1,0)
比如你自动机的初始状态是 (1,0)即a=1,b=0时,运行程序的下一个状态就是(1,1).
画图出来就是 这4个状态作为顶点,并且有下面几条边
(0,0) --> (0,0)(自环),(1,0)-->(1,1),(1,1)-->(1,1)(自环),(0,1)-->(0,1)自环
存在的意义就是一种理论模型,也可以认为是一种编程思想.词法分析系也离不开 if else,这一系列的if else和条件也就组成自动机.
最经典体现自动机思想的算法就是KMP算法,你肯定学过,字符串子串匹配的算法.回忆这个算法的过程:算法第一步构造的next表(数据结构教材的说法)其实就是根据子串的内容构造了一个自动机!算法第二步将原串作为自动机输入,自动机的输出就是匹配到的子串位置或者无匹配.

❸ !!编译原理DFA和NFA

DFA或NFA是对计算机程序的行为的抽象模型。你编写的程序其实就对应了一个自动机。简单举例来说,如果a,b可以取值0或1; 程序: if(a==1) b=1; 这个程序对应了一个自动机。
对应的自动机就有状态 (0,0), (0,1), (1,1), (1, 0)
比如你自动机的初始状态是 (1,0)即a=1,b=0时,运行程序的下一个状态就是(1,1)。

画图出来就是 这4个状态作为顶点,并且有下面几条边
(0,0) --> (0,0)(自环), (1,0)-->(1,1), (1,1)-->(1,1)(自环), (0,1)-->(0,1)自环

存在的意义就是一种理论模型,也可以认为是一种编程思想。 词法分析系也离不开 if else, 这一系列的if else和条件也就组成自动机。。。

最经典体现自动机思想的算法就是KMP算法,你肯定学过,字符串子串匹配的算法。 回忆这个算法的过程:算法第一步构造的next表(数据结构教材的说法)其实就是根据子串的内容构造了一个自动机! 算法第二步将原串作为自动机输入,自动机的输出就是匹配到的子串位置或者无匹配。

❹ 编译原理中的lookhead描述的是什么意思

lookahead 就是向前看。在语法分析过程中,分析器根据当前已经扫描过的标记流,再加上尚未扫描的标记,确定怎样分析这个句子。如果只看一个尚未处理的标记就能确定怎么进行下一步分析,就叫做Lookahead 1,如果需要看两个才能确定,就叫做Lookahead 2,依此类推。

❺ 正在学习编译原理,语法图应该用什么软件画会比较简单一点

一般用YACC画,不过建议用GOLD PARSER。画起来最快,不要编程。
步骤:
1)写出正确的文法。
2)在测试窗口中输入要分析的字符串。

❻ 编译原理-LL1文法详细讲解

我们知道2型文法( CFG ),它的每个产生式类型都是 α→β ,其中 α ∈ VN , β ∈ (VN∪VT)*。

例如, 一个表达式的文法:

最终推导出 id + (id + id) 的句子,那么它的推导过程就会构成一颗树,即 CFG 分析树:

从分析树可以看出,我们从文法开始符号起,不断地利用产生式的右部替换产生式左部的非终结符,最终推导出我们想要的句子。这种方式我们称为自顶向下分析法。

从文法开始符号起,不断用非终结符的候选式(即产生式)替换当前句型中的非终结符,最终得到相应的句子。
在每一步推导过程中,我们需要做两个选择:

因为一个句型中,可能存在多个非终结符,我们就不确定选择那一个非终结符进行替换。
对于这种情况,我们就需要做强制规定,每次都选择句型中第一个非终结符进行替换(或者每次都选择句型中最后一个非终结符进行替换)。

自顶向下的语法分析采用最左推导方式,即总是选择每个句型的最左非终结符进行替换。

最终的结果是要推导出一个特定句子(例如 id + (id + id) )。
我们将特定句子看成一个输入字符串,而每一个非终结符对应一个处理方法,这个处理方法用来匹配输入字符串的部分,算法如下:

方法解析:

这种方式称为递归下降分析( Recursive-Descent Parsing ):

当选择的候选式不正确,就需要回溯( backtracking ),重新选择候选式,进行下一次尝试匹配。因为要不断的回溯,导致分析效率比较低。

这种方式叫做预测分析( Predictive Parsing ):

要实现预测分析,我们必须保证从文法开始符号起,每一个推导过程中,当前句型最左非终结符 A 对于当前输入字符 a ,只能得到唯一的 A 候选式。

根据上面的解决方法,我们首先想到,如果非终结符 A 的候选式只有一个以终结符 a 开头候选式不就行了么。
进而我们可以得出,如果一个非终结符 A ,它的候选式都是以终结符开头,并且这些终结符都各不相同,那么本身就符合预测分析了。

这就是S_文法,满足下面两个条件:

例子:

这就是一个典型的S_文法,它的每一个非终结符遇到任一终结符得到候选式是确定的。如 S -> aA | bAB , 只有遇到终结符 a 和 b 的时候,才能返回 S 的候选式,遇到其他终结符时,直接报错,匹配不成功。

虽然S_文法可以实现预测分析,但是从它的定义上看,S_文法不支持空产生式(ε产生式),极大地限制了它的应用。

什么是空产生式(ε产生式)?

例子

这里 A 有了空产生式,那么 S 的产生式组 S -> aA | bAB ,就可以是 a | bB ,这样 a , bb , bc 就变成这个文法 G 的新句子了。

根据预测分析的定义,非终结符对于任一终结符得到的产生式是确定的,要么能获取唯一的产生式,要么不匹配直接报错。

那么空产生式何时被选择呢?

由此可以引入非终结符 A 的后继符号集的概念:
定义: 由文法 G 推导出来的所有句型,可以出现在非终结符 A 后边的终结符 a 的集合,就是这个非终结符 A 的后继符号集,记为 FOLLOW(A) 。

因此对于 A -> ε 空产生式,只要遇到非终结符 A 的后继符号集中的字符,可以选择这个空产生式。
那么对于 A -> a 这样的产生式,只要遇到终结符 a 就可以选择了。

由此我们引入的产生式可选集概念:
定义: 在进行推导时,选用非终结符 A 一个产生式 A→β 对应的输入符号的集合,记为 SELECT(A→β)

因为预测分析要求非终结符 A 对于输入字符 a ,只能得到唯一的 A 候选式。
那么对于一个文法 G 的所有产生式组,要求有相同左部的产生式,它们的可选集不相交。

在 S_文法基础上,我们允许有空产生式,但是要做限制:

将上面例子中的文法改造:

但是q_文法的产生式不能是非终结符打头,这就限制了其应用,因此引入LL(1)文法。

LL(1)文法允许产生式的右部首字符是非终结符,那么怎么得到这个产生式可选集。
我们知道对于产生式:

定义: 给定一个文法符号串 α , α 的 串首终结符集 FIRST(α) 被定义为可以从 α 推导出的所有串首终结符构成的集合。

定义已经了解清楚了,那么该如何求呢?
例如一个文法符号串 BCDe , 其中 B C D 都是非终结符, e 是终结符。

因此对于一个文法符号串 X1X2 … Xn ,求解 串首终结符集 FIRST(X1X2 … Xn) 算法:

但是这里有一个关键点,如何求非终结符的串首终结符集?

因此对于一个非终结符 A , 求解 串首终结符集 FIRST(A) 算法:

这里大家可能有个疑惑,怎么能将 FIRST(Bβ) 添加到 FIRST(A) 中,如果问文法符号串 Bβ 中包含非终结符 A ,就产生了循环调用的情况,该怎么办?

对于 串首终结符集 ,我想大家疑惑的点就是,串首终结符集到底是针对 文法符号串 的,还是针对 非终结符 的,这个容易弄混。
其实我们应该知道, 非终结符 本身就属于一个特殊的 文法符号串
而求解 文法符号串 的串首终结符集,其实就是要知道文法符号串中每个字符的串首终结符集:

上面章节我们知道了,对于非终结符 A 的 后继符号集 :
就是由文法 G 推导出来的所有句型,可以出现在非终结符 A 后边的终结符的集合,记为 FOLLOW(A) 。

仔细想一下,什么样的终结符可以出现在非终结符 A 后面,应该是在产生式中就位于 A 后面的终结符。例如 S -> Aa ,那么终结符 a 肯定属于 FOLLOW(A) 。

因此求非终结符 A 的 后继符号集 算法:

如果非终结符 A 是产生式结尾,那么说明这个产生式左部非终结符后面能出现的终结符,也都可以出现在非终结符 A 后面。

我们可以求出 LL(1) 文法中每个产生式可选集:

根据产生式可选集,我们可以构建一个预测分析表,表中的每一行都是一个非终结符,表中的每一列都是一个终结符,包括结束符号 $ ,而表中的值就是产生式。
这样进行语法推导的时候,非终结符遇到当前输入字符,就可以从预测分析表中获取对应的产生式了。

有了预测分析表,我们就可以进行预测分析了,具体流程:

可以这么理解:

我们知道要实现预测分析,要求相同左部的产生式,它们的可选集是不相交。
但是有的文法结构不符合这个要求,要进行改造。

如果相同左部的多个产生式有共同前缀,那么它们的可选集必然相交。
例如:

那么如何进行改造呢?
其实很简单,进行如下转换:

如此文法的相同左部的产生式,它们的可选集是不相交,符合现预测分析。

这种改造方法称为 提取公因子算法

当我们自顶向下的语法分析时,就需要采用最左推导方式。
而这个时候,如果产生式左部和产生式右部首字符一样(即A→Aα),那么推导就可能陷入无限循环。
例如:

因此对于:

文法中不能包含这两种形式,不然最左推导就没办法进行。

例如:

它能够推导出如下:

你会惊奇的发现,它能推导出 b 和 (a)* (即由 0 个 a 或者无数个 a 生成的文法符号串)。其实就可以改造成:

因此消除 直接左递归 算法的一般形式:

例如:

消除间接左递归的方法就是直接带入消除,即

消除间接左递归算法:

这个算法看起来描述很多,其实理解起来很简单:

思考 : 我们通过 Ai -> Ajβ 来判断是不是间接左递归,那如果有产生式 Ai -> BAjβ 且 B -> ε ,那么它是不是间接左递归呢?
间接地我们可以推出如果一个产生式 Ai -> αAjβ 且 FIRST(α) 包括空串ε,那么这个产生式是不是间接左递归。

❼ 编译原理中 “句子”的概念 LR(1)分析法中“L” “ R”的含义分别是

字母表上符合某种规则构成的串称作句子。
L:自左至右扫描,R:最右推倒的逆过程。

❽ 编译原理LL1语法分析的例子谁有

这个句子要分成两大部分看:1.He said that....2.All things considered, he thought it was a bad idea.
2是1的宾语从句,但复杂的是在2这个宾语从句中包含了一个独立主格结构(All things considered),其实2的核心主语和谓语应该是he和thought,此时all things是独立于这个核心主语的,我们叫它独立主格,此时considered不是谓语动词,而是非谓语,在这里表示被动,所以all things considered不是一句完整的话(完整的应该是all things are considered)这里all things 是独立主格considered是它的非谓语,一起构成一个独立主格结构,和后面句子放在一起构成主句的宾语从句,是符合语法的。

❾ 编译原理LR分析法中的SLR(1)分析表和LR分析过程、语法树怎么求

第二题和第三题拿去,刚做的:


由B->cAa|c就可知该文法不是LR(0)文法了


❿ 学了编译原理这门课,要求编一个:词法分析的程序,要求对词法分析至少选择三种不同类型的句子进行单词识

给你一个toyl语言的
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<windows.h>
#define is_end_of_input(ch) ((ch)=='#')
#define is_letter(ch) ('A'<=(ch)&&(ch)<='Z'||'a'<=(ch)&&(ch)<='z')
#define is_digit(ch) ('0'<=(ch)&&(ch)<='9')
#define is_digit_or_letter(ch) (is_letter(ch)||is_digit(ch))
#define is_operator(ch) ((ch)=='+'||(ch)='-'||(ch)='*')
#define is_layout(ch) (!is_end_of_input(ch)&&(ch)<=' ')
#define Step 10 //字符串每次增长的长度.

typedef struct
{
char * Class;
char seman[];
int len;
int value;
}mytoken;

typedef struct node
{
char words[20];
int length;
int time;
struct node *next;
}mynode;
//全局变量
char ch;
char *fp;
mytoken token;
int TYPE=-1;
int num=1;
int j=0;
int Length=0;
void error()//报错
{
printf("错误\n");
}

char * getstr() //从键盘获取任意长度的输入函数实现
{
char *temp, *str=(char *)malloc(10);
int c=0, len=0, times=1, number=0;
if(!str)
{
printf("内存不足!");
return (char *)NULL;
}
number+=times*Step;

do //遇到#则输入结束。
{
c=getchar();
if(len==number)
{
times++;
number=times*Step;
temp=str;
str=(char *)realloc(str,number);
if(str==NULL)
{
printf("内存不足!");
str=temp;
break;
}
}
*(str+len)=c;
len++;
}while(c!='#');
str=(char *)realloc(str,len+1); //字符串的最终长度调整.
*(str+len)='\0';
return str;
}

void next_char(void)//获取下一个字符
{
ch=*fp;
fp=fp+1;

}

void next_valchar(void)//获取第一个有效的字符,过滤空格等。
{
next_char();
if(ch=='#')exit(0);//当文件只有空格和#号时
while(is_layout(ch))
{
next_char();
//if(ch=='#')exit(0);
}
}

void back()//指针回走
{
fp=fp-1;
}

void recongnize_name(char chr)//识别字符串
{
char name[10];
int i=0;
name[i++]=ch;
next_char();
while(is_digit_or_letter(ch))
{
name[i++]=ch;
next_char();

}

if((ch!=' ')&&(ch!='\t')&&(ch!='\n')&&(ch!='#')&&(ch!=':')&&(ch!='(')&&(ch!=')')&&(ch!=';'))//转非法字符串处理
{

do
{
name[i++]=ch;
next_char();

}while((ch!=' ')&&(ch!='\t')&&(ch!='\n')&&(ch!='#'));
if((name[i-1]=='#')||(name[i-1]=='\n'))//去掉结束符#或回车
{
name[i-1]='\0';
}
back();//指针回走
name[i]='\0';
printf("非法字符串\t%s\n",name);

}
else{
name[i]='\0';
if (name== "begin")
{
token.Class="BEGIN";
}
else if (name== "end")
{
token.Class="END";
}
else if (name=="read")
{
token.Class=="READ";
}
else if (name=="write")
{
token.Class="WRITE";
}
else
{
token.Class="IDEN";
int n=0;
Length=0;
while(name[n]!='\0')
{

token.seman[n]=name[n];
n++;
}
Length=n;
token.seman[n]=name[n];

}
back();
}
}

void recongnize_number(char cha)//识别数字
{
int N=0;
int m;
char name[10];//存非法字符串
int i=0;
while((m=is_digit(ch)))
{
N=N*10+(ch-'0');

name[i++]=ch;
next_char();
}
if(ch==' '||ch=='\t'||ch=='\n'||ch=='#'||(ch==';'))
{
token.Class="NUMB";
token.value=N;
back();
}
else//转非法字符串处理
{

do
{
name[i++]=ch;
next_char();

}while((ch!=' ')&&(ch!='\t')&&(ch!='\n')&&(ch!='#'));
if((name[i-1]=='#')||(name[i-1]=='\n'))//去掉结束符#或回车
{
name[i-1]='\0';
}
back();//指针回走
name[i]='\0';
printf("非法字符串\t%s\n",name);
TYPE=-1;

}

}

int next_token(void)//读下一个单词
{
next_valchar();
char name[10];//存首字母非法的字符串
int fg=0;
int i=0;
if('0'<=(ch)&&(ch)<='9')
{
TYPE=0;
}
else if('A'<=(ch)&&(ch)<='Z'||'a'<=(ch)&&(ch)<='z')
{
TYPE=1;
}
else
{
TYPE=2;
}

switch(TYPE)
{
case 0:
recongnize_number(ch);break;
case 1:
recongnize_name(ch);break;
case 2:
switch(ch)
{
case '+' :
token.Class="ADD";
token.seman[0]='+';
token.seman[1]='\0';
TYPE=2;
break;
case '*' :
token.Class="MULT";
token.seman[0]='*';
token.seman[1]='\0';
TYPE=2;
break;
case ':' :
next_char();
if(ch!='=')
{
error();
TYPE=-1;
break;
}
token.Class="ASS";
token.seman[0]=':';
token.seman[1]='=';
token.seman[2]='\0';
TYPE=2;
break;
case ';' :
token.Class="SEMI";
token.seman[0]=';';
token.seman[1]='\0';
TYPE=2;
break;
case '(' :
token.Class="OPEN";
token.seman[0]='(';
token.seman[1]='\0';
TYPE=2;
break;
case ')' :
token.Class="CLOSE";
token.seman[0]=')';
token.seman[1]='\0';
TYPE=2;
break;
default :
fg=1;
break;

}
}
if(fg==1)//非法字符串处理
{
name[i++]=ch;
while((ch!=' ')&&(ch!='\t')&&(ch!='\n')&&(ch!='#'))
{
next_char();
name[i++]=ch;
}
if((name[i-1]=='#')||(name[i-1]=='\n'))//去掉结束符#或回车

{
name[i-1]='\0';
}
back();//指针回走
name[i]='\0';
printf("非法字符串\t%s\n",name);
TYPE=-1;//置TYPE为-1
}

}

int compare(node *head,char words[],int Length)//单词的比较
{
node *p;
p=head;
if(head==NULL)
{
return 0;
}
else
{

int fg=1;

do
{
int i,j,succ;
i=0;
succ=0;
while((i<=p->length-Length)&&(!succ))
{
j=0;
succ=1;
while((j<Length)&&succ)
{
if(words[j]==(p->words[i+j]))
{
j++;
}
else
{
succ=0;
}

}
i++;
}
if(succ&&(j>=p->length))
{
(p->time)++;
fg=0;

}
if(p->next!=NULL)
{
p=p->next;
}

}while((p->next!=NULL)&&fg);

if(fg==0)
{
return 1;
}
else
{
return 0;
}

}
}

node *insert(node *head) //将读到的新单词加入链表
{
node *p;
p=(mynode*)malloc(sizeof(mynode));/*分配空间*/
strcpy(p->words,token.seman);
int n=0;
p->length=0;
p->time=1;
while(p->words[n]!='\0')
{
p->length++;
n++;
}
p->next=NULL;
if(head==NULL)
{
head=p;
}
else
{
p->next=head->next;
head->next=p;
}

return head;
}

void display(node *head)//打印链表的内容
{
node *p;
p=head;
if(!p) printf("\n无标识符!");
else
{
printf("\n各标识符或保留字及其出现的次数为:\n");
printf("标识符\t出现次数\n");
while(p) { printf("%s\t%d\n",p->words,p->time);p=p->next;}

}
}

int main(int argc, char *argv[])
{
char *str1=NULL;
printf("请输入程序代码:\n");
str1=getstr();//获取用户程序段的输入
fp=str1;
mynode *head=NULL;
do{
next_token();

switch(TYPE)
{
case 0:
printf("[%d]\t(%s,\t\"%d\")\n",num++,token.Class,token.value);
break;
case 1:
case 2:
printf("[%d]\t(%s,\t\"%s\")\n",num++,token.Class,token.seman);
int f;
f=0;
f=compare(head,token.seman,Length);
if((TYPE==1)&&(f==0))
{

head=insert(head);
}
break;
default:
break;
}

}while(*fp!='#');

display(head);
return 0;
}

热点内容
python获取坐标 发布:2025-04-05 11:49:44 浏览:932
excel2003加密方法 发布:2025-04-05 11:32:30 浏览:851
公司路由器地址改变服务器地址 发布:2025-04-05 11:32:27 浏览:499
帝豪第四代豪华型有哪些配置 发布:2025-04-05 11:31:41 浏览:12
玩和平精英的时候服务器发呆了怎么办 发布:2025-04-05 11:02:40 浏览:382
怎么把苹果的号转到安卓手机上 发布:2025-04-05 10:39:05 浏览:534
存储核心架构瓶颈已被攻破 发布:2025-04-05 10:38:27 浏览:308
空间新算法 发布:2025-04-05 10:33:21 浏览:708
蜀门和远征哪个配置低 发布:2025-04-05 10:23:50 浏览:288
linux下jdk的安装 发布:2025-04-05 10:12:20 浏览:70