编译原理 虎书 读书笔记

Ch2


Is it wrong?

Each state can be picked or not, so the number of combinations should be 2^n.


Ch3

1. What is recursive descendent?

From http://en.wikipedia.org/wiki/Recursive_descent_parser:

In computer science, a recursive descent parser is a kind of top-down parser built from a set of mutually recursive procedures (or a non-recursive equivalent) where each such procedure usually implements one of the production rules of the grammar. Thus the structure of the resulting program closely mirrors that of the grammar it recognizes.

predictive parser is a recursive descent parser that does not require backtracking. Predictive parsing is possible only for the class of LL(k) grammars, which are the context-free grammars for which there exists some positive integer k that allows a recursive descent parser to decide which production to use by examining only the next k tokens of input. The LL(k) grammars therefore exclude all ambiguous grammars, as well as all grammars that contain left recursion. Any context-free grammar can be transformed into an equivalent grammar that has no left recursion, but removal of left recursion does not always yield an LL(k) grammar. A predictive parser runs in linear time.

Recursive descent with backtracking is a technique that determines which production to use by trying each production in turn. Recursive descent with backtracking is not limited to LL(k) grammars, but is not guaranteed to terminate unless the grammar is LL(k). Even when they terminate, parsers that use recursive descent with backtracking may require exponential time.

Although predictive parsers are widely used, and are frequently chosen if writing a parser by hand, programmers often prefer to use a table-based parser produced by a parser generator, either for an LL(k) language or using an alternative parser, such as LALR or LR. This is particularly the case if a grammar is not in LL(k) form, as transforming the grammar to LL to make it suitable for predictive parsing is involved. Predictive parsers can also be automatically generated, using tools like ANTLR.

Predictive parsers can be depicted using transition diagrams for each non-terminal symbol where the edges between the initial and the final states are labelled by the symbols (terminals and non-terminals) of the right side of the production rule.[1]


2. LL, LR?

http://blog.csdn.net/younggift/article/details/9416361


3. BNF?

介绍(来自维基百科)

BNF 规定是推导规则(产生式)的集合,写为:

<符号> ::= <使用符号的表达式>

这里的 <符号> 是非终结符,而表达式由一个符号序列,或用指示选择的竖杠'|' 分隔的多个符号序列构成,每个符号序列整体都是左端的符号的一种可能的替代。从未在左端出现的符号叫做终结符

基本原理
      BNF类似一种数学游戏:从一个符号开始(叫做起始标志,实例中常用S表示),然后给出替换前面符号的规则。BNF语法定义的语言只不过是一个字符串集合,你可以按照下述规则书写,这些规则叫做书写规范(生产式规则),形式如下:
      symbol := alternative1 | alternative2 ...
      每条规则申明:=左侧的符号必须被右侧的某一个可选项代替。替换项用“|”分割(有时用“::=”替换“:=”,但意思是一样的)。替换项通常有两个符号和终结符构成。之所以叫做终结符是因为没有针对他们的书写规范,他们是书写过程的终止(符号通常被叫做非终止符,也有人叫非终端)。


       BNF就是巴科特·瑙尔式的缩写, 在计算机的史前时代(1950s),曾有一位大师,他奠定了现代计算机的基础,在他老人家的诸多成就之中,包括了对形式语言的研究,和发明了高级语言:FORTRAN。 为了纪念他老人家,我们把他提出的一套描述语言的方法叫做BNF。它以递归方式描述语言中的各种成分,凡遵守其规则的程序就可保证语法上的正确性。BNF由于其简洁、明了、科学而被广泛接受,成为描述各种程序设计语言的最常用的工具。
       其实BNF很简单,::=表示定义     |表示或    尖括号(<>)括起来的是非终结符 
  所谓非终结符就是语言中某些抽象的概念不能直接出现在语言中的符号,终结符就是可以直接出现在语言中的符号。
  比如:C语言的声明语句可以用BNF这样描述: 
  <声明语句> ::= <类型><标识符>; | <类型><标识符>[<数字>]; 
  这一句中<声明语句>这个非终结符被定义成了两种形式(上面用|隔开的两部分),同时在这里引入了三个终结符: 分号; 左方括号[,右方括号 ]。 
  <类型> ::= <简单类型> | <指针类型> | <自定义类型> 
  <指针类型> ::= <简单类型> * | <自定义类型> * 
  <简单类型> ::= int|char|double|float|long|short|void 
  <自定义类型> ::= enum<标识符>|struct<标识符>|union<标识符>|<标识符>
  到这里就基本上把<类型>定义清楚了。

  <数字> ::= 0x<十六进制数字串> | 0<八进制数字串> | <十进制数字串> 
  <十六进制数字串> ::= <十六进制数字> | <十六进制数字串><十六进制数字> 
  <八进制数字串> ::= <八进制数字> | <八进制数字串><八进制数字> 
  <十进制数字串> ::= <十进制数字> | <十进制数字串><十进制数字> 
  <十六进制数字> ::= <十进制数字> | A | B | C | D | E | F 
  <十进制数字> ::= <八进制数字> | 8 | 9 
  <八进制数字> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 
  到这里就把<数字>定义清楚了 

  <标识符> ::= <字母> | <标识符> <字母数字串> 
  <字母数字串> ::= <字母>|<十进制数字>|<字母数字串><字母>|<字母数字串><十进制数字> 
  <字母> ::= _ | <大写字母> | <小写字母> 
  <小写字母> ::= a|b|c|d|e|f|g|h|i|j ……  
  <大写字母> ::= A|B|C|D|E|F|G|H|I|J …… 
  到此为止整个声明语句就定义完了(就是说已经没有非终结符了)。

         虽然看起来很繁,但前面定义的各种非终结符都可以很容易的在别的地方重用。比如,函数声明可以定义成下面的样子: 
  <函数声明语句> ::= <类型><标识符>(<形参表>); 
  <形参表> ::= <类型><标识符> | <形参表>,<形参表> 
  只用两句就描述完了,所以BNF实际上比用自然语言要简练得多(整个C语言只用一二百句就可以描述清楚),而且相当的精确,不会有自然语言中那种模棱两可的表达。如果你对BNF比较敏感的话,会发现C里面的标识符不能由数字开头,而且在C里面下划线是被当做字母看待的(也就是说能用字母的地方都可以用下划线)。
  另外,还有一种EBNF就没有正宗的BNF这么爽了,也有很多人在用,前面的那些递归的定义被写成了{}。
   有一段时间PASCAL爱好者们喜欢用一个叫语法图的东西,画出来很难看,但功能和BNF差不多,现在好象已经没多少人用了。
     近几年流行另一种东西: 
  digit = on
e of 0 1 2 3 4 5 6 7 8 9 

  这里非终结符digit用斜体表示,one of是这种方法里定义的一个量词(常用斜黑体)。


4. AST?

在计算机科学中,抽象语法树abstract syntax tree或者缩写为AST),或者语法树syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现;而类似于if-condition-then这样的条件跳转语句,可以使用带有两个分支的节点来表示。

和抽象语法树相对的是具体语法树(concrete syntax tree),通常称作分析树(parse tree)。一般的,在源代码的翻译和编译过程中,语法分析器创建出分析树。一旦AST被创建出来,在后续的处理过程中,比如语义分析阶段,会添加一些信息。

什么是分析树

对一个串按照某种文法进行推导的过程,可以用一颗树表示出来。这棵树就是分析树。
什么是抽象语法树?
分析树是表述记号串结构的一种十分有用的表示法。在分析树中,记号表现为分析树的树叶(自左至右),而分析树的内部节点则表示推导的各个步骤(按某种顺序)。但是,分析树却包括了比纯粹为编译生成可执行代码所需更多的信息。为了看清这一点,可根据简单你的表达式文法,考虑表达式3+4的分析树:
这棵树成功的表现了串的含义。可是还有一个更简单的能表示与这相同的信息,那就是树: 
 这种树是真正的源代码序列的抽象表示。虽然不能从其中重新得到记号序列(不同于分析树),但他们却包含了转换所需要的所有信息,且比分析树高效,这样的树称作抽象语法树(abstract syntax tree)或 语法树(syntax tree).。分析程序可以通过一颗分析树表示出所有步骤,但却只能构造出一个抽象语法树(或与它等同的)。

Tiger Ch4:




你可能感兴趣的:(Reading,Notes)