编译原理的项目
㈠ 请问大家在实际项目中用到过编译原理吗
我跟你说,编译原理太有用了。
我是做手机游戏的,现在做一个游戏引擎。既然是引擎,就需要提供抽象的东西给上层使用。这里,我引入了脚本系统。
这个脚本系统包括一堆我根据实际需求自行设计的指令集,包括基本的输入输出,四则运算,系统功能调用,函数声明,调用等等(其实你要是用过lua或者其他游戏脚本你就知道了。)整个结构包括指令集、编译器、虚拟机等部分。这样,引擎提供一些基础服务,比如绘图,计算位置等,脚本就可以非常简单控制游戏。甚至快速构建新游戏。你应该知道QUAKE引擎吧?
这里提供给你一个计算器的小程序,应用了EBNF理论,支持表达式,比如(2+3*6)*4+4,你自己体验一下它的简洁和强大。
/*
simple integer arithmetic calculator according to the EBNF
<exp> -> <term>{<addop><term>}
<addop>->+|-
<term>-><factor>{<mulop><factor>}
<mulop> -> *
<factor> -> ( <exp> )| Number
Input a line of text from stdin
Outputs "Error" or the result.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char token;/*global token variable*/
/*function prototypes for recursive calls*/
int exp(void);
int term(void);
int factor(void);
void error(void)
{
fprintf(stderr,"Error\n");
exit(1);
}
void match(char expectedToken)
{
if(token==expectedToken)token=getchar();
else error();
}
main()
{
int result;
token = getchar();/*load token with first character for lookahead*/
result = exp();
if(token=='\n')/*check for end of line */
printf("Result = %d\n",result);
else error();/*extraneous cahrs on line*/
return 0;
}
int exp(void)
{
int temp = term();
while((token=='+')||(token=='-'))
switch(token)
{
case '+':
match('+');
temp+=term();
break;
case '-':
match('-');
temp-=term();
break;
}
return temp;
}
int term(void)
{
int temp = factor();
while (token=='*')
{
match('*');
temp*=factor();
}
return temp;
}
int factor(void)
{
int temp;
if(token=='('){
match('(');
temp = exp();
match(')');
}
else if(isdigit(token)){
ungetc(token,stdin);
scanf("%d",&temp);
token = getchar();
}
else error();
return temp;
}
其实编程学到一定程度总是没有方向了,总是在问学C/C++下一步怎么学啊,觉得掌握了该语言了云云,实际上,你缺少的就是这些软的东西,缺少的是理论。
编译原理不是单一的理论,它涵盖了一个niche,里面可以学到很多其他知识,比如正则表达式、BNF、EBNF、分析树、语法树还有很多运行时环境等知识
这些给你带来的是非常丰厚的回报。不说多了,学完运行时,你就会加深对C++语言本身的理解。
㈡ 编译原理 A产生空和B的规约在一个项目集里是规约冲突吗
如果我们把同心的项目集合合并为一,就可能导致冲突,但是这种冲突不会是移进-规约冲突.因为如果存在这种冲突,则意味着对当前输入符号a,有一个项目[A→α.,a]要求以A→α进行规约,同时又有另一个项目[B→β.aγ,b]要求把a移进.这两个项目既然同处于合并之后的项目集中,则意味着在合并前,必有某个c使得[A→α.,a]和[B→β.aγ,c]同处于合并前的某一集合中.然而,这又意味着原来的LR(1)项目集就已经存在移进-规约冲突.从而文法不是LR(1)的,这与假设不符.事实上移进-规约冲突不依赖于搜索符号而只依赖于其心,因此,同心集合的合并不会引起新的移进-规约冲突
㈢ 编译原理中LR(1) 那个向前搜索符怎么求的 跪求高手解答 复制粘贴或者答非所问的别来
1、首先第一步就是项目[S’-> . S,],自动生成搜索符],自动生成搜索符],自动生成搜索符,从项目[A->α.Bβ,?]生成项目[B->…,first(β)]。
㈣ 计算机科学与技术中编译原理简答题
时间有点久记得不太真切,用通俗语言说,希望题主尽量查阅书籍参考资料自行验证理解。
1、什么是移进项目,什么是规约项目
这个是自顶向下和自下向上分析时候用到的。所谓移进就是不处理,所谓规约就是处理,合并,替换。比如当前符合某个正规式左部,就用这个正规式右部替换左部,称为规约。两种操作的目的都是为了分析整体是否符合语法树。
2、请给出生成C语言语句序列的文法(假定s表示任意一个语句,它为终结符)
关于这个,我感觉你描述的不是很清楚,因为C语言文法包含的正规式还是挺多的,如果单指statement的话,
statement_listà
statement
| statement_list statement
Statementà
| compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
再配合上相应的终结符。
3、能用上下文无关文法生成正规集吗?为什么?
可以。不过无法保证不含冲突。
4、计算first集和follow集对于构造自顶向下的语法分析器有什么作用?
可以用来排除冲突。例如移进-移进冲突,移进-规约冲突。
5、是否可能存在这样一个DFA,它的所有状态都是接受状态,包括其实状态,为什么?
这个爱莫能助,据我的构想是可以的,但是这样的DFA最终都会成为单一状态DFA。
㈤ 编译原理中,LR(0)文法的项目集规范族的I0,I1,I2,I3…………是怎么求的~
先举个例子:
}
将其命名为I1。
其他可类似推出。
㈥ 编译原理项目集规范族问题GO(I,X)中的X是安什么顺序进行测试的
这个问题本身不太准确。
GO(I,X)是一个转换函数,它的定义如下:
GO(I,X)中的X是一个文法符号,可以是终结符或非终结符,CLOSURE(J)是J的闭包函数,闭包函数的定义就不多说了。
问题“GO(I,X)中的X是按什么顺序进行测试”,是否可解释成“X是按出现在产生式中的顺序进行测试”
㈦ 编译原理的发展历程
在20世纪40年代,由于冯·诺伊曼在存储-程序计算机方面的先锋作用,编写一串代码或程序已成必要,这样计算机就可以执行所需的计算。开始时,这些程序都是用机器语言 (machine language )编写的。机器语言就是表示机器实际操作的数字代码,例如:
C7 06 0000 0002 表示在IBM PC 上使用的Intel 8x86处理器将数字2移至地址0 0 0 0 (16进制)的指令。
但编写这样的代码是十分费时和乏味的,这种代码形式很快就被汇编语言(assembly language )代替了。在汇编语言中,都是以符号形式给出指令和存储地址的。例如,汇编语言指令 MOV X,2 就与前面的机器指令等价(假设符号存储地址X是0 0 0 0 )。汇编程序(assembler )将汇编语言的符号代码和存储地址翻译成与机器语言相对应的数字代码。
汇编语言大大提高了编程的速度和准确度,人们至今仍在使用着它,在编码需要极快的速度和极高的简洁程度时尤为如此。但是,汇编语言也有许多缺点:编写起来也不容易,阅读和理解很难;而且汇编语言的编写严格依赖于特定的机器,所以为一台计算机编写的代码在应用于另一台计算机时必须完全重写。
发展编程技术的下一个重要步骤就是以一个更类似于数学定义或自然语言的简洁形式来编写程序的操作,它应与任何机器都无关,而且也可由一个程序翻译为可执行的代码。例如,前面的汇编语言代码可以写成一个简洁的与机器无关的形式 x = 2。
在1954年至1957年期间,IBM的John Backus带领的一个研究小组对FORTRAN语言及其编译器的开发,使得上面的担忧不必要了。但是,由于当时处理中所涉及到的大多数程序设计语言的翻译并不为人所掌握,所以这个项目的成功也伴随着巨大的辛劳。几乎与此同时,人们也在开发着第一个编译器, Noam Chomsky开始了他的自然语言结构的研究。他的发现最终使得编译器结构异常简单,甚至还带有了一些自动化。Chomsky的研究导致了根据语言文法(grammar ,指定其结构的规则)的难易程度以及识别它们所需的算法来为语言分类。正如现在所称的-与乔姆斯基分类结构(Chomsky hierarchy )一样-包括了文法的4个层次:0型、1型、2型和3型文法,且其中的每一个都是其前者的专门化。2型(或上下文无关文法(context-free grammar ))被证明是程序设计语言中最有用的,而且今天它已代表着程序设计语言结构的标准方式。
分析问题( parsing problem ,用于限定上下文无关语言的识别的有效算法)的研究是在20世纪60年代和70年代,它相当完善地解决了这一问题, 现在它已是编译理论的一个标准部分。它们与乔姆斯基的3型文法相对应。对它们的研究与乔姆斯基的研究几乎同时开始,并且引出了表示程序设计语言的单词(或称为记号)的符号方式。
人们接着又深化了生成有效的目标代码的方法,这就是最初的编译器,它们被一直使用至今。人们通常将其误称为优化技术(optimization technique ),但因其从未真正地得到过被优化了的目标代码而仅仅改进了它的有效性,因此实际上应称作代码改进技术(code improvement technique )。
这些程序最初被称为编译程序-编译器,但更确切地应称为分析程序生成器 (parser generator ),这是因为它们仅仅能够自动处理编译的一部分。这些程序中最着名的是 Yacc (yet another compiler- compiler),它是由Steve Johnson在1975年为Unix系统编写的。
类似地,有穷自动机的研究也发展了另一种称为扫描程序生成器 (scanner generator )的工具,Lex (与Yacc同时,由Mike Lesk为Unix系统开发的)是这其中的佼佼者。在20世纪70年代后期和80年代早期,大量的项目都关注于编译器其他部分的生成自动化,这其中就包括代码生成。这些尝试并未取得多少成功,这大概是因为操作太复杂而人们又对其不甚了解。
编译器设计最近的发展包括:首先,编译器包括了更为复杂的算法的应用程序,它用于推断或简化程序中的信息;这又与更为复杂的程序设计语言(可允许此类分析)的发展结合在一起。其中典型的有用于函数语言编译的Hindle y - Milner类型检查的统一算法。
其次,编译器已越来越成为基于窗口的交互开发环境(interactive development environment,IDE )的一部 分,它包括了编辑器、链接程序、调试程序以及项目管理程序。这样的IDE的标准并没有多少, 但是已沿着这一方向对标准的窗口环境进行开发了。