当前位置:首页 » 编程软件 » 编译器ast解析

编译器ast解析

发布时间: 2023-05-15 02:19:18

① C语言VC编译器出现无法解析的外部命令LNK200

C语言中,要写成 struct DirList,不可以直接 DirList

② 用Java怎么解析C/C++代码生成AST抽象语法树结构

其中一个明显的例子是Eclipse CDT里的parser。
它是完全用Java实现的,手写的递归下降parser,能把C或C++源码parse成AST供Eclipse CDT的IDE功能使用。它支持C99语法(包括GCC扩展)、C++语法(我没仔细看现在支持到什么版本了)等。
它并不用于实际的编译(这跟Eclipse JDT里的Eclipse Compiler for Java不同);实际编译还是交给诸如GCC、xlc之类的编译器去完成。
关于Eclipse CDT里的C与C++ parser的介绍,请参考

③ “编译”与“编译器”是什么意思

编译是动词
编译器是名词
编译(compilation , compile)
1、利用编译程序从源语言编写的源程序产生目标程序的过程。
2、用编译程序产生目标程序的动作。

编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。
编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;中间代码生成;代码优化;目标代码生成。主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,给出提示信息。
(1) 词法分析
词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号,把作为字符串的源程序改造成为单词符号串的中间程序。执行词法分析的程序称为词法分析程序或扫描器。
源程序中的单词符号经扫描器分析,一般产生二元式:单词种别;单词自身的值。单词种别通常用整数编码,如果一个种别只含一个单词符号,那么对这个单词符号,种别编码就完全代表它自身的值了。若一个种别含有许多个单词符号,那么,对于它的每个单词符号,除了给出种别编码以外,还应给出自身的值。
词法分析器一般来说有两种方法构造:手工构造和自动生成。手工构造可使用状态图进行工作,自动生成使用确定的有限自动机来实现。
(2) 语法分析
编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。编译程序的语法规则可用上下文无关文法来刻画。
语法分析的方法分为两种:自上而下分析法和自下而上分析法。自上而下就是从文法的开始符号出发,向下推导,推出句子。而自下而上分析法采用的是移进归约法,基本思想是:用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里,当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分归约成该产生式的左邻符号。
(3) 中间代码生成
中间代码是源程序的一种内部表示,或称中间语言。中间代码的作用是可使编译程序的结构在逻辑上更为简单明确,特别是可使目标代码的优化比较容易实现。中间代码即为中间语言程序,中间语言的复杂性介于源程序语言和机器语言之间。中间语言有多种形式,常见的有逆波兰记号、四元式、三元式和树。
(4) 代码优化
代码优化是指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。所谓等价,是指不改变程序的运行结果。所谓有效,主要指目标代码运行时间较短,以及占用的存储空间较小。这种变换称为优化。
有两类优化:一类是对语法分析后的中间代码进行优化,它不依赖于具体的计算机;另一类是在生成目标代码时进行的,它在很大程度上依赖于具体的计算机。对于前一类优化,根据它所涉及的程序范围可分为局部优化、循环优化和全局优化三个不同的级别。
(5) 目标代码生成
目标代码生成是编译的最后一个阶段。目标代码生成器把语法分析后或优化后的中间代码变换成目标代码。目标代码有三种形式:
① 可以立即执行的机器语言代码,所有地址都重定位;
② 待装配的机器语言模块,当需要执行时,由连接装入程序把它们和某些运行程序连接起来,转换成能执行的机器语言代码;
③ 汇编语言代码,须经过汇编程序汇编后,成为可执行的机器语言代码。
目标代码生成阶段应考虑直接影响到目标代码速度的三个问题:一是如何生成较短的目标代码;二是如何充分利用计算机中的寄存器,减少目标代码访问存储单元的次数;三是如何充分利用计算机指令系统的特点,以提高目标代码的质量。
编译器,是将便于人编写,阅读,维护的高级计算机语言翻译为计算机能解读、运行的低阶机器语言的程序。编译器将原始程序(Source program)作为输入,翻译产生使用目标语言(Target language)的等价程序。源代码一般为高阶语言 (High-level language), 如 Pascal、C++、Java 等,而目标语言则是汇编语言或目标机器的目标代码(Object code),有时也称作机器代码(Machine code)。
一个现代编译器的主要工作流程如下:
源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 汇编程序 (assembler) → 目标代码 (object code) → 连接器 (Linker) → 可执行程序 (executables)

工作原理
[编辑本段]

编译是从源代码(通常为高阶语言)到能直接被计算机或虚拟机执行的目标代码(通常为低阶语言或机器语言)的翻译过程。然而,也存在从低阶语言到高阶语言的编译器,这类编译器中用来从由高阶语言生成的低阶语言代码重新生成高阶语言代码的又被叫做反编译器。也有从一种高阶语言生成另一种高阶语言的编译器,或者生成一种需要进一步处理的的中间代码的编译器(又叫级联)。
典型的编译器输出是由包含入口点的名字和地址, 以及外部调用(到不在这个目标文件中的函数调用)的机器代码所组成的目标文件。一组目标文件,不必是同一编译器产生,但使用的编译器必需采用同样的输出格式,可以链接在一起并生成可以由用户直接执行的可执行程序。

编译器种类
[编辑本段]

编译器可以生成用来在与编译器本身所在的计算机和操作系统(平台)相同的环境下运行的目标代码,这种编译器又叫做“本地”编译器。另外,编译器也可以生成用来在其它平台上运行的目标代码,这种编译器又叫做交叉编译器。交叉编译器在生成新的硬件平台时非常有用。“源码到源码编译器”是指用一种高阶语言作为输入,输出也是高阶语言的编译器。例如: 自动并行化编译器经常采用一种高阶语言作为输入,转换其中的代码,并用并行代码注释对它进行注释(如OpenMP)或者用语言构造进行注释(如FORTRAN的DOALL指令)。

预处理器(preprocessor)

作用是通过代入预定义等程序段将源程序补充完整。

编译器前端(frontend)

前端主要负责解析(parse)输入的源代码,由语法分析器和语意分析器协同工作。语法分析器负责把源代码中的‘单词’(Token)找出来,语意分析器把这些分散的单词按预先定义好的语法组装成有意义的表达式,语句 ,函数等等。 例如“a = b + c;”前端语法分析器看到的是“a, =, b , +, c;”,语意分析器按定义的语法,先把他们组装成表达式“b + c”,再组装成“a = b + c”的语句。 前端还负责语义(semantic checking)的检查,例如检测参与运算的变量是否是同一类型的,简单的错误处理。最终的结果常常是一个抽象的语法树(abstract syntax tree,或 AST),这样后端可以在此基础上进一步优化,处理。

编译器后端(backend)

编译器后端主要负责分析,优化中间代码(Intermediate representation)以及生成机器代码(Code Generation)。

一般说来所有的编译器分析,优化,变型都可以分成两大类: 函数内(intraproceral)还是函数之间(interproceral)进行。很明显,函数间的分析,优化更准确,但需要更长的时间来完成。

编译器分析(compiler analysis)的对象是前端生成并传递过来的中间代码,现代的优化型编译器(optimizing compiler)常常用好几种层次的中间代码来表示程序,高层的中间代码(high level IR)接近输入的源代码的格式,与输入语言相关(language dependent),包含更多的全局性的信息,和源代码的结构;中层的中间代码(middle level IR)与输入语言无关,低层的中间代码(Low level IR)与机器语言类似。 不同的分析,优化发生在最适合的那一层中间代码上。

常见的编译分析有函数调用树(call tree),控制流程图(Control flow graph),以及在此基础上的 变量定义-使用,使用-定义链(define-use/use-define or u-d/d-u chain),变量别名分析(alias analysis),指针分析(pointer analysis),数据依赖分析(data dependence analysis)等等。

上述的程序分析结果是编译器优化(compiler optimization)和程序变形(compiler transformation)的前提条件。常见的优化和变新有:函数内嵌(inlining),无用代码删除(Dead code elimination),标准化循环结构(loop normalization),循环体展开(loop unrolling),循环体合并,分裂(loop fusion,loop fission),数组填充(array padding),等等。 优化和变形的目标是减少代码的长度,提高内存(memory),缓存(cache)的使用率,减少读写磁盘,访问网络数据的频率。更高级的优化甚至可以把序列化的代码(serial code)变成并行运算,多线程的代码(parallelized,multi-threaded code)。

机器代码的生成是优化变型后的中间代码转换成机器指令的过程。现代编译器主要采用生成汇编代码(assembly code)的策略,而不直接生成二进制的目标代码(binary object code)。即使在代码生成阶段,高级编译器仍然要做很多分析,优化,变形的工作。例如如何分配寄存器(register allocatioin),如何选择合适的机器指令(instruction selection),如何合并几句代码成一句等等。

编译语言与直译语言对比
[编辑本段]

许多人将高阶程序语言分为两类: 编译型语言 和 直译型语言 。然而,实际上,这些语言中的大多数既可用编译型实现也可用直译型实现,分类实际上反映的是那种语言常见的实现方式。(但是,某些直译型语言,很难用编译型实现。比如那些允许 在线代码更改 的直译型语言。)

历史
[编辑本段]

上世纪50年代,IBM的John Backus带领一个研究小组对FORTRAN语言及其编译器进行开发。但由于当时人们对编译理论了解不多,开发工作变得既复杂又艰苦。与此同时,Noam Chomsky开始了他对自然语言结构的研究。他的发现最终使得编译器的结构异常简单,甚至还带有了一些自动化。Chomsky的研究导致了根据语言文法的难易程度以及识别它们所需要的算法来对语言分类。正如现在所称的Chomsky架构(Chomsky Hierarchy),它包括了文法的四个层次:0型文法、1型文法、2型文法和3型文法,且其中的每一个都是其前者的特殊情况。2型文法(或上下文无关文法)被证明是程序设计语言中最有用的,而且今天它已代表着程序设计语言结构的标准方式。分析问题(parsing problem,用于上下文无关文法识别的有效算法)的研究是在60年代和70年代,它相当完善的解决了这个问题。现在它已是编译原理中的一个标准部分。

有限状态自动机(Finite Automaton)和正则表达式(Regular Expression)同上下文无关文法紧密相关,它们与Chomsky的3型文法相对应。对它们的研究与Chomsky的研究几乎同时开始,并且引出了表示程序设计语言的单词的符号方式。

人们接着又深化了生成有效目标代码的方法,这就是最初的编译器,它们被一直使用至今。人们通常将其称为优化技术(Optimization Technique),但因其从未真正地得到过被优化了的目标代码而仅仅改进了它的有效性,因此实际上应称作代码改进技术(Code Improvement Technique)。

当分析问题变得好懂起来时,人们就在开发程序上花费了很大的功夫来研究这一部分的编译器自动构造。这些程序最初被称为编译器的编译器(Compiler-compiler),但更确切地应称为分析程序生成器(Parser Generator),这是因为它们仅仅能够自动处理编译的一部分。这些程序中最着名的是Yacc(Yet Another Compiler-compiler),它是由Steve Johnson在1975年为Unix系统编写的。类似的,有限状态自动机的研究也发展了一种称为扫描程序生成器(Scanner Generator)的工具,Lex(与Yacc同时,由Mike Lesk为Unix系统开发)是这其中的佼佼者。

在70年代后期和80年代早期,大量的项目都贯注于编译器其它部分的生成自动化,这其中就包括了代码生成。这些尝试并未取得多少成功,这大概是因为操作太复杂而人们又对其不甚了解。

编译器设计最近的发展包括:首先,编译器包括了更加复杂算法的应用程序它用于推断或简化程序中的信息;这又与更为复杂的程序设计语言的发展结合在一起。其中典型的有用于函数语言编译的Hindley-Milner类型检查的统一算法。其次,编译器已越来越成为基于窗口的交互开发环境(Interactive Development Environment,IDE)的一部分,它包括了编辑器、连接程序、调试程序以及项目管理程序。这样的IDE标准并没有多少,但是对标准的窗口环境进行开发已成为方向。另一方面,尽管近年来在编译原理领域进行了大量的研究,但是基本的编译器设计原理在近20年中都没有多大的改变,它现在正迅速地成为计算机科学课程中的中心环节。

在九十年代,作为GNU项目或其它开放源代码项目标一部分,许多免费编译器和编译器开发工具被开发出来。这些工具可用来编译所有的计算机程序语言。它们中的一些项目被认为是高质量的,而且对现代编译理论感兴趣的人可以很容易的得到它们的免费源代码。

大约在1999年,SGI公布了他们的一个工业化的并行化优化编译器Pro64的源代码,后被全世界多个编译器研究小组用来做研究平台,并命名为Open64。Open64的设计结构好,分析优化全面,是编译器高级研究的理想平台。

④ ast树开源

您好,AST树是Abstract Syntax Tree的缩写,它是一种抽象语法树,是一种用于表示程序语法结构改凳的数据结构。它链运可以用核唤旅来表示编程语言的语法结构,用于描述程序语言的语法结构,以及用于程序分析和编译器的实现。AST树可以用来表示程序的语法结构,以及用于程序分析和编译器的实现。AST树的开源实现有很多,比如ANTLR,Eclipse AST,JavaCC,JastAdd等。它们都是用来提供AST树的开源实现,可以用来构建编译器,解释器,代码分析器,以及其他程序分析工具。

⑤ 编译器内部使用了哪些技术

编译器是一种将高级语言代码转换为机器语言代码的工具。在编译器内部,使用了许多技术来实现代码的转换和优化。

其中一些常见的技术包括:

词法分析器(Lexer):将源代码转换为一个个标记(Token),并去除无用的空格和注释。

语法分析器(Parser):将标记转换为抽象语法树(AST),并举隐检查语正虚厅法是否正确。

语义分析器(Semantic Analyzer):对AST进行分析,检查变量、函数、类型等是否符合规范,并进行类型检查等操作。

优誉早化器(Optimizer):对生成的机器语言代码进行优化,以提高代码的执行效率和空间利用率。

代码生成器(Code Generator):将优化后的代码生成可执行的机器语言代码。

调试器(Debugger):用于调试生成的代码,可以在代码执行过程中进行断点调试、变量监视等操作。

编译器内部使用这些技术,可以提高代码的执行效率、减少代码出错的概率,并方便程序员进行调试和维护。
码字不易,希望能帮到您! 求采纳...

⑥ C++编译器变量未初始化错误解析

变量未初始化是C++编程中最为常见和易犯的错误之一。在C++中丛族,为变量所分配的内存空间并不是完全“干净的”,也不会在分配空间时自动做清零处理。其结果就是,一个未初雹慎始化的变量将包含某个值,但没办法准确地知道这个值是多少。此外,每次执行这个程序的时候,该变量的值可能都会源郑敬发生改变。这就有可能产生间歇性发作的问题,是特别难以追踪的。

php程序编译中常见错误信息及解释

编写程序时 无论怎样小心谨慎 犯错总是在所难免的 这些错误通常会迷惑PHP编译器 如果开发人员无法了解编译器报错信息的含义 那么这些错误信息不仅毫无用处 还会常常让人感到沮丧 编译PHP脚本时 PHP编译器会尽其所能报告它遇到的第一个问题 这样就产生一个问题 只有当错误出现时 PHP才能将它识别出来(本文后面对此问题进行了详细描述) 正是由于这个缘故 编译器指出出错的那行 从表面上看来可能语法正确无误 或者可能是根本就不存在的一行!更好地理解错误信息可以大大节省确定并改正错误内容所花费的时间 因此 在本文中 我将努力阐明多种不同类型的PHP报错信息 以及在开发过程中如何正确理解各种报错信息的含义 本文中所讲述的内容与您所应用的PHP的版本无关 因为本文所描述的各种错误并不限定于某一特殊版本的特定错误 另外我们假定您是一位初级或者中级程序员 并已经从事编程工作有半年或一年的时间 编译器的工作方式要搞清楚编译器为什么会报告某一行上存在错误 首先必须明确编译器解析PHP代码的机制 我并不打算在本文中对此进行详细论述 但是 我们将会讨论一些更易于引发错误的简单概念 变量声明如果在一条语句中声明一个变量 具体方式如下所示 $variable = value ;编译器首先求出语句右半部分的值(即等号右边的所有内容) 在一些编程书籍中 将此表示为语句的 RHS (右半部分) 恰恰正是语句的这一部分常常会引发错大逗误 如果使用的语法不正确 就会出现解析错误 解析错误Parse error:解析错误 unexpected T_WHILE in c://program files//apache group//apache//htdocs//script php on line 每次确定了前一错误时 解析错误一个接一个地不断出现 因为PHP在第一个解析错误之后就停止执行脚本 调试并纠正这一系列的错误往往会让人觉得特别厌烦 而且 解析错误具有很少的信息 几乎不报告错误所在的行号 具体原因就是当出现错误时 编译器判定好几行的语法看起来应该是有效的 直至遇到无效的语法 最可能的情形就是表达式中使用了预定义的字词 例如;while = ; // Bad ? while 就是一个预定义字词 不能分配给一个值预定义的字词包括 while function等 如果PHP使用 uses to evaluate your code 您不能使用这些预定义字词来命名变量 而且如果您非要这样做的话 PHP就会报出更多的慎胡错误 这是您无法忍受 关于这个问题 下面的示例可能会对您有所帮助 请咨询阅读一下下面所示的PHP 代码 $b = somevalueif($b == somevalue){print Hello world!;}?>错误位于$b =一行(在语句的末端缺少分号) 所以错误应该是解析错误:第 行缺少分号对吧?而不应该依据解析器判定的 Parse error: parse error unexpected T_IF in c://program files//apachegroup//apache//htdocs//ereg php on line 在第 行 if() 语句的语法是正确的 那么 编译器是被什么给搞糊涂了呢?线索就是unexpected T_IF 部分 出现 unexpected T_???错误时 它所表示的含义为 编译器发现在预定义字不应该出现的位置出现 T_IF 代表 if() T_WHILE 代表 while() T_FOR 代表 for()等 值得庆幸的是 一些错误的原因也很简单 语句没有使用分号(;)结束 比如上面的示例 字符串中缺少引号 其他一些常见的错误我见过的最常见的错误就是 当没有使用大括号( } )结束一个函数或者一个循环时出现的错误 这很可能是最常见 最让人烦的错误 具体代码如下滚孝卖 function UselessFunction() {for($i < ; $i < ; $i++){}将产生下列错误 Parse error: parse error unexpected $ in c://program files//apachegroup//apache//htdocs//ereg php on line 由于函数 UselessFunction 没有使用大括号( } )来结束 PHP编译器不断查找表示结束的大括号直至到达文件末尾为止 因为编译器未找到一个匹配的大括号 就会报告文件末尾处有错误 如果正确地反映了代码的层次结构 错误信息就会变得非常明显 如果没有标明代码的层次结构 那么最后要想查清楚到底忘记了什么也会变得几乎是不可能的 所以 请记住 一定要标明代码的层次结构 Tab键可以很容易地实现这一点 对后续的开发人员来说 把握代码框架并对其进行修改也会更容易一些 Mysql 错误另一极其令人讨厌的错误信息就是最常见的MySQL错误 这常常使 PHP新手感到颇为头疼 Warning: Supplied argument is not a valid MySQL result resource in 上面所报告有错的一行可能是 while($row = mysql_fetch_array($result)) {参数 $result并不是一个有效的资源 在英语中它表示因为查询失败 将无法处理mysql_fetch_array 任一查询的语法无效(您应该将查询复制 粘贴到MySQL 控制台参考来进行测试) 或者与数据库的连接失败(这种情况下您应该再次检查用户名和口令等) 防止错误发生第一步 智能代码器可采取以下几步来消除下列错误出现 · 在每一条语句的末尾处 不必考虑添加分号——这应该成为一种习惯 · 总是要尽可能标明代码的层次结构 这可以使您能够查看是否忘记在if 调用或函数末端等位置添加大括号 · 请使用可突出显示语法的编辑器(如 HTML Kit) 有了这类编辑器的辅助 您就能确定是否忘记了添加引号 是否缺少分号等 lishixin/Article/program/PHP/201311/21338

⑧ C++编译器整数除法错误解析

C++中的大多数二元操作都要求两搭闷颂个操作数是同一类型。如果操作数的不同类型,其中一个操作数会提升到和另一个操作数相匹配的类型。在C++中,知郑除法操作符可以被看做是2个不同的操作:其中一个操作于整数之上,另一个是操作于浮点数之上。如果操作数是浮点数类罩前型,除法操作将返回一个浮点数的值。

⑨ 如何用python写一个解释器

大学里计算机科学最吸引我的地方就是编译器。最神奇的是,编译器是如何读出我写的那些烂代码,并且还能生成那么复杂的程序。当我终于选了一门编译方面的课程时,我发现这个过程比我想的要简单得多。
在本系列的文章中,我会试着通过为一种基本命令语言IMP写一个解释器,来展示这种简易性。因为IMP是一个简单广为人知的语言,所以打算用 Python写这个解释器。Python代码看起来很像伪代码,所以即使你不认识 Python,你也能理解它。解析可以通过一套从头开始实现的解析器组合完成(在本系列的下一篇文章中会有解释)。除了sys(用于I/O)、re(用于解析正则表达式)以及unittest(用于确保一切工作正常)库,没有使用其他额外的库。
IMP 语言
在开始写之前,我们先来讨论一下将要解释的语言。IMP是拥有下面结构的最小命令语言:
赋值语句(所有变量都是全局的,而且只能存储整数):

Python

1

x := 1

条件语句:

Python

1
2
3
4
5

if x = 1 then
y := 2
else
y := 3
end

while循环:

Python

1
2
3

while x < 10 do
x := x + 1
end

复合语句(分号分隔):

Python

1
2

x := 1;
y := 2

OK,所以它只是一门工具语言,但你可以很容易就把它扩展成比Lua或python更有用的语言。我希望能把这份教程能保持尽量简单。
下面这个例子是计算阶乘的程序:

Python

1
2
3
4
5
6

n := 5;
p := 1;
while n > 0 do
p := p * n;
n := n - 1
end

IMP没有读取输入的方式,所以初始状态必须是在程序最开始写一系列的赋值语句。也没有打印结果的方式,所以解释器必须在程序的结尾打印所有变量的值。
解释器的结构
解释器的核心是“中间表示”(Intermediate representation,IR)。这就是如何在内存中表示IMP程序。因为IMP是一个很简单的语言,中间表示将直接对应于语言的语法;每一种表达和语句都有对应的类。在一种更复杂的语言中,你不仅需要一个“语法表示”,还需要一个更容易分析或运行的“语义表示”。
解释器将会执行三个阶段:
将源码中的字符分割成标记符(token)
将标记符组织成一棵抽象语法树(AST)。抽象语法树就是中间表示。
评估这棵抽象语法树,并在最后打印这棵树的状态
将字符串分割成标记符的过程叫做“词法分析”,通过一个词法分析器完成。关键字是很短,易于理解的字符串,包含程序中最基本的部分,如数字、标识符、关键字和操作符。词法分析器会除去空格和注释,因为它们都会被解释器忽略。

将标记符组织成抽象语法树(AST)的过程称为“解析过程”。解析器将程序的结构提取成一张我们可以评估的表格。

实际执行这个解析过的抽象语法树的过程称为评估。这实际上是这个解析器中最简单的部分了。
本文会把重点放在词法分析器上。我们将编写一个通用的词汇库,然后用它来为IMP创建一个词法分析器。下一篇文章将会重点打造一个语法分析器和评估计算器。
词汇库
词法分析器的操作相当简单。它是基于正则表达式的,所以如果你不熟悉它们,你可能需要读一些资料。简单来说,正则表达式就是一种能描述其他字符串的特殊的格式化的字符串。你可以使用它们去匹配电话号码或是邮箱地址,或者是像我们遇到在这种情况,不同类型的标记符。
词法分析器的输入可能只是一个字符串。简单起见,我们将整个输入文件都读到内存中。输出是一个标记符列表。每个标记符包括一个值(它代表的字符串)和一个标记(表示它是一个什么类型的标记符)。语法分析器会使用这两个数据来决定如何构建一棵抽象语法树。
由于不论何种语言的词法分析器,其操作都大同小异,我们将创建一个通用的词法分析器,包括一个正则表达式列表和对应的标签(tag)。对每一个表达式,它都会检查是否和当前位置的输入文本匹配。如果匹配,匹配文本就会作为一个标记符被提取出来,并且被加上该正则表达式的标签。如果该正则表达式没有标签,那么这段文本将会被丢弃。这样免得我们被诸如注释和空格之类的垃圾字符干扰。如果没有匹配的正则表达式,程序就要报错并终止。这个过程会不断循环直到没有字符可匹配。
下面是一段来自词汇库的代码:

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

import sys
import re

def lex(characters, token_exprs):
pos = 0
tokens = []
while pos < len(characters):
match = None
for token_expr in token_exprs:
pattern, tag = token_expr
regex = re.compile(pattern)
match = regex.match(characters, pos)
if match:
text = match.group(0)
if tag:
token = (text, tag)
tokens.append(token)
break
if not match:
sys.stderr.write('Illegal character: %sn' % characters[pos])
sys.exit(1)
else:
pos = match.end(0)
return tokens

注意,我们遍历正则表达式的顺序很重要。lex会遍历所有的表达式,然后接受第一个匹配成功的表达式。这也就意味着,当使用词法分析器时,我们应当首先考虑最具体的表达式(像那些匹配算子(matching operator)和关键词),其次才是比较一般的表达式(像标识符和数字)。
词法分析器
给定上面的lex函数,为IMP定义一个词法分析器就非常简单了。首先我们要做的就是为标记符定义一系列的标签。IMP只需要三个标签。RESERVED表示一个保留字或操作符。INT表示一个文字整数。ID代表标识符。

Python

1
2
3
4
5

import lexer

RESERVED = 'RESERVED'
INT = 'INT'
ID = 'ID'

接下来定义词法分析器将会用到的标记符表达式。前两个表达式匹配空格和注释。它们没有标签,所以 lex 会丢弃它们匹配到的所有字符。

Python

1
2
3

token_exprs = [
(r'[ nt]+', None),
(r'#[^n]*', None),

然后,只剩下所有的操作符和保留字了。记住,每个正则表达式前面的“r”表示这个字符串是“raw”;Python不会处理任何转义字符。这使我们可以在字符串中包含进反斜线,正则表达式正是利用这一点来转义操作符比如“+”和“*”。

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

(r':=', RESERVED),
(r'(', RESERVED),
(r')', RESERVED),
(r';', RESERVED),
(r'+', RESERVED),
(r'-', RESERVED),
(r'*', RESERVED),
(r'/', RESERVED),
(r'<=', RESERVED),
(r'<', RESERVED),
(r'>=', RESERVED),
(r'>', RESERVED),
(r'=', RESERVED),
(r'!=', RESERVED),
(r'and', RESERVED),
(r'or', RESERVED),
(r'not', RESERVED),
(r'if', RESERVED),
(r'then', RESERVED),
(r'else', RESERVED),
(r'while', RESERVED),
(r'do', RESERVED),
(r'end', RESERVED),

最后,轮到整数和标识符的表达式。要注意的是,标识符的正则表达式会匹配上面的所有的保留字,所以它一定要留到最后。

Python

1
2
3

(r'[0-9]+', INT),
(r'[A-Za-z][A-Za-z0-9_]*', ID),
]

既然正则表达式已经定义好了,我们还需要创建一个实际的lexer函数。

Python

1
2

def imp_lex(characters):
return lexer.lex(characters, token_exprs)

如果你对这部分感兴趣,这里有一些驱动代码可以测试输出:

Python

1
2
3
4
5
6
7
8
9
10
11

import sys
from imp_lexer import *

if __name__ == '__main__':
filename = sys.argv[1]
file = open(filename)
characters = file.read()
file.close()
tokens = imp_lex(characters)
for token in tokens:
print token

继续……

⑩ hive核心组件及流程(一)

依赖第三方组件: Meta store(mysql),hdfs,MapRece
hive:
Client客户端 CLI、JDBC
Driver连接客户端与服务端的桥梁
SQL Pareser解析器,将SQL转换为抽象语法树AST
1.将HQL语句转换为Token
2.对Token进行解析,生成AST
Physical Plan编译器将AST编译生成逻激虚帆辑誉磨执行计划
Query Optimizer优化器,对逻辑执行计划进行优化
1.将AST转换为QueryBlock
2.将QueryBlock转换为OperatorTree
3.OperatorTree进行逻辑优化
4.生成TaskTree
5.TaskTree执行物理优化
Execution执行器把逻辑执行计划转换成可以运行的物理计划
1.获取MR临时工作目录
3.定义Mapper和Recer
2.定义Partitioner
4.实例化Job
5.提交Job

1.以Antlr定义的语法规则,对SQL完成词法解析,将SQL转换为AST
2.遍历AST,抽象出查询基本组成单元QueryBlock。
3.遍历QueryBlock,将其转换为OperatorTree,逻辑执行单元
4.利用逻辑优化器对OperatorTree进行逻辑优化。
5.遍历OperatorTree转换为TaskTree,将逻辑执行计划转化为物理执行计划
6.使用物理优化器对TaskTree进行物理优化
7.生成最终的执行计划,提交执行

$HIVE_HOME/bin/hive可以进入客户端

$HIVE_HOME/bin/hive -e "{SQL语句}"可以执行SQL语句

$HIVE_HOME/bin/hive -f {SQL文件名.sql}可以执行sql文件

开启hiveserver2服务,可以通过JDBC提交SQL

创建Driver
创建OptionsProcessor
初始化log4j
标准输入输出以及错误输出流的定义,后续需要输入 SQL 以及打印控制台信息
解析输入的参数,包含"-e -f -v -database"
读取输入的sql
按照";"分割的方式解析
解析单行SQL
遇到为"quit"或者"exit"退出
遇到为"source"开头,执行 SQL 文件,读取文件并解析
如果命令以"!"开头,则表示用户需要执行 shell命令
以上三种都不是的情况下执行SQL,进行SQL解析

获取当前系统时间
获取系统结束时间
编译SQL语句
SQL生成AST,构建词法解析器,将关键词替换为TOKEN,明雹进行语法解析,生成最终AST
处理AST,转换为QueryBlock然后转换为OperatorTree,对Operator进行逻辑优化,然后转换为任务树,然后进行物理优化。
根据任务树构建MrJob
添加启动任务,根据是否可以并行来决定是否并行启动Task
设置MR任务的InputFormat、OutputFormat 等等这些 MRJob 的执行类
构建执行MR任务的命令
向yarn提交任务
打印头信息
获取结果集并获取抓取到的条数
打印SQL执行时间及数据条数

热点内容
比较便宜的云服务器 发布:2025-07-13 18:29:59 浏览:406
切换ftp 发布:2025-07-13 18:29:07 浏览:738
锐龙哪个配置最高画质 发布:2025-07-13 18:22:34 浏览:196
压缩机工作原理图 发布:2025-07-13 18:10:15 浏览:39
黑暗追求者安卓怎么联机 发布:2025-07-13 18:10:07 浏览:617
北大保安自学编程 发布:2025-07-13 18:09:58 浏览:858
java递归排列 发布:2025-07-13 18:02:43 浏览:473
轻量云服务器如何换成d盘 发布:2025-07-13 17:58:45 浏览:931
重置腾讯云服务器时间 发布:2025-07-13 17:54:55 浏览:326
aes256java加密 发布:2025-07-13 17:54:46 浏览:710