Electronic Joint Business

Solution for E-Business

bison

操作系统开发初体验 (1)

文章评价:
如果你正在读这篇文章,没准你想知道更多有关如何创建自己的 OS 方面的内容。不过你首先要知道,我这短短几篇文章是没办法涵盖 OS 开发的各个方面的。我会介绍一些 OS 的基础知识,但还需要靠你自己去研读相关的技术文档,这样你才能明白操作系统为何如此工作。确定还想读下去吗?好,让我们开始吧。

理解 OS 开发很关键的一点是:一切将从零开始,你直接和硬件打交道。你会遇到硬件故障,也不能指望系统每次都如期工作。你没有标准库可供使用,更没有 .NET 框架或者Java 虚拟机。一切只能靠你自己。

开始之前,你要了解系统控制权是如何转交到你手上的。很奇怪的是,没有什么标准规定电脑开机之后应置于什么状态,唯一能确定的是,开机之后一定会去执行引导扇区,它位于可启动的存储介质的起始部分,会被加载到内存地址 0x7C00 处,其长度为 512字节,并以 0xAA55 作为文件末尾签名。引导扇区通常用汇编语言编写。为了节约时间,我们将使用现成的 GRUB (Grand Unified Bootloader)。这可为后续工作提供可靠的基础,并将电脑置于同一个标准状态。

Grub 会将电脑置于以下状态:

  • 保护模式
  • A20 地址线启用
  • 寄存器 EBX 存有指向多重启动信息结构(Multiboot information structure)的指针
  • 寄存器 EAX 存有固定值 0x2BADB002
  • 分页机制关闭
  • 栈位于内存的某处
  • 中断机制关闭

下面我会逐一介绍这些状态。保护模式允许内核开发人员按虚拟地址空间访问最大为 4GB 的内存,并引入了保护环“Ring”的概念。以下几小节会介绍更多的内容。 A20 门电路是键盘控制器附近的一条“古老”的地址线。它最初设计是为了与 8086 保持兼容,在“关闭”的时候,屏蔽了对内存开始部分 1M 以上地址的访问。

>>> 阅读全文

 

, , , , , , , ,

Flex 和 Bison 简介 (三) 支持 C++

和一些收费软件相比,Flex 和 Bison 在某一些方面还是相对比较的弱的,比如说 Flex 对 C++ 的支持还处在实验状态,这意味着在将来的版本中有可能发生较大的改动,而且目前的解决方案在一些细节上处理得还并不好,但作为一个免费软件,Flex 和 Bison 总体上还是非常不错的软件,而且生成的词法生成器不依赖于其他库文件,可移植性比较好。

如果你更倾向于 Flex 和 Bison ,而不是用我们在第二节末尾提到的商业收费软件 Parser Generator 来生成资源模板解析器,那么请跟随本文来了解一下 Flex 和 Bison 是如何支持 C++ 的。

Flex 对 C++ 支持的基本是通过继承来完成的。在头文件 FlexLexer.h中定义了两个类 FlexLexer 和 yyFlexLexer。前者是一个抽象类,定义了 Flex 所生成的词法分析器的接口(interface),比如yylex();后者则继承自FlexLexer,是词法分析器的实现类,封装了词法分析器用到的状态变量等。因此,在默认的 C++ 模式下,Flex 的任务就是根据 “.l” 源文件自动生成 yyFlexLexer 中各成员函数的定义。规则的动作代码自然是被合成为 yyFlexLexer::yylex() 的实现啦,因此在规则动作中我们访问的变量和函数实际都是 yyFlexLexer 类的成员(或者是yylex()的参数 ),而不再是全局变量或全局函数。这便是 Flex 对 C++ 解决方案的基本原理。

这里还有一个问题。即在默认情况下,Flex 把生成的代码都放在了 yyFlexLexer 这一个类里,而事实上,实现类是应该有多个的,尤其是当我们的程序需要多个词法分析器的时候,每个词法分析器都应该对应一个实现类。Flex 是怎么解决这个问题的呢?事实上,在包含进这个头文件之前,”yyFlexLexer” 已经被定义为一个宏,其默认值为”yyFlexLexer”,而 Flex 提供了一些机制来重新定义这个宏,这样就能避免命名冲突的问题啦。关于这个问题我们先讲这么多,下面我们先详细讨论在默认情况下的具体做法,再回来讨论定制的问题。

为了让它跑起来,有两件最基本的事情是必须做的。首先,要在文件的定义段打开 c++ 选项,即添加 “%option c++” 一行。 或者在命令行使用 “-+” 选项也是一样的。打开这个选项之后,Flex 就会生成 C++ 代码,生成的代码会默认输出到 lex.yy.cc文件中(后缀不是”.c”啦)。可是如果这个时候直接编译(使用命令$ flex abc.l && g++ lex.yy.cc),则会收到链接出错的提示:”undefined reference to yyFlexLexer::yywrap()”。怎么回事呢?是不是忘记添库文件啦?仔细想一想,这个错误其实是在抱怨yyFlexLexer::yywrap()函数没有定义。原来,Flex 忘记帮我们生成一个默认的 yywrap() 的定义啦。其实这也不能怪 Flex 粗心,因为即便在 c 的情况下,它也不会自动合成这个函数的定义,我们之所以使用 C 语言时没有收到这个链接错误,只是因为在 fl 库中提供了一个默认的实现而已,因此如果我们自己不写,链接器就会把 fl 库中的那一个链接进来啦。可是,这种方法在 C++ 的环境下就不工作,因为这个是一个类的成员函数,而不是全局的啦。

>>> 阅读全文

 

, ,

编写 GCC 前端

文章评价:
一、简介
这篇文章演示了如何为 GCC 创建新的前端的基本步骤,它可以帮你在 GCC 编译工具链的基础上创建自己的编译器。另外本文还囊括了一些基础工具的使用方法,如 Bison 和 Flex。阅读本文需要 C 语言的基础知识。你还可以参考介绍编译器基本原理的文章,这可以让你更好地理解相关的内容。1

本文会演示如何在 GCC 编译工具链中添加一种新的迷你语言。虽然 GNU Internal 这部手册已经详细介绍了 GCC 的内部机理,但对新手来说,其内容实在多得可怕。通过本文中的例子,新手也可以开始着手摆弄复杂的 GCC 基础代码。

二、编译器基础知识
编译器本质上就是个翻译器,它读入程序的源代码并将其转换成目标语言,目标语言通常是真实(或虚拟)处理器的汇编代码。设计一个真正的编译器是项复杂的工作,需要有计算机科学和数学的正规课程的背景。

整个编译过程可分为一定量的子任务,也被称为阶段(phase)。通常会涉及以下阶段:

  • 词法分析 – Lexical analysis
  • 语法分析 – Syntax analysis
  • 生成中间代码 – Intermediate code generation
  • 代码优化 – Code Optimization
  • 代码生成 – Code generation

上述所有阶段都会用到符号表错误处理器。我们先来看一下这些阶段:

>>> 阅读全文

 

, , ,

Flex 和 Bison 简介 (二)

在上一篇文章中,我们讨论了如何用 flex 和 Bison 来 创建词法分析器(标记识别器)和解析器。本文是本系列文章的第二篇,我们将会看到如何用这些工具来创建可以读取 Visual Studio 6 资源文件的解析器。本文将重点关注于词法分析器。

不过考虑到这两个工具的密切联系,我们会在解析器和词法分析器之间来回跳转。在本文的最后,你可以下载到词法分析器和解析器的源代码。

如我们在第一篇文章中讨论的,词法分析器负责从某处读取输入流,并将其分解成一连串的标记。每个标记代表着最底层的构造块,用于表示诸如字符串、 数字或关键字等等东西。词法分析器通过将输入数据和一系列正则表达式 (规则) 相匹配来实现实现这一点。当它找到和特定规则的一个匹配时,它会执行将程序员所编写的一些执行代码,并向解析器返回一个标记,用于表明哪个规则被匹配了。它还可能会返回一些与规则关联的数据。

例如下面的正则表达式。

/* Decimal numbers */
-?[09]+    {
        yylval.ival = atoi(yytext);
        return NUMBER;
    }

该表达式会匹配以负号开头的包含至少一个数的十进制数序列。(有关正则表达式的含义和格式,你可以参考:http://www.monmouth.com/~wstreett/lex-yacc/flex_1.html 并搜索的”模式”)。当找到匹配时,它会调用 atoi 函数并将字符串 yytext 传递给它作为参数,yytext 正好是符合规则的字符串。另一方面,atoi 的返回值被赋给在解析器中定义的联合 yylval 的成员 ival。最后该操作会返回一个 NUMBER 标记给解析器并终止。

>>> 阅读全文

 

, , , , ,

Flex 和 Bison 简介(一)

文章评价:
我最近有个项目需要一个对话框编辑器,客户要求该编辑器能够加载对话框模板,并显示出相应的对话框。

具体的实现方法有简单的,也有复杂的。简单的方法只需将资源脚本编译成 .res 文件,然后让程序读取这些编译过的模板,由此得到对话框模板的句柄,并传递给 CreateDialogIndirect 函数。这样就可以用代码来检查每个控件的属性。但这种方法有个缺点:一旦修改过模板就必须重新编译资源脚本,否则将导致严重的逻辑错误。

有鉴于此,我舍易求难:实现一个能读取 Visual Studio6 资源文件 (.rc 文件)的解析器来检查每个控件的属性,然后再返回编译过的对话框模板。

如果你浏览过资源模板文件的源文件,你会发现自己动手从头开始实现这样一个解析器是不可能的。资源文件包含各种文本块,其中有注释、工具栏资源、菜单、对话框等等。每种文本块都有固定的格式。要用面向过程的方法来编写解析这些文本块的程序,要解决的问题实在多如牛毛。还好我们有 Flex 和 Bison 来提供支持。

什么是 Flex 和 Bison?
既然提到 Flex 和 Bison 就不能不说到其前身 Yacc 和 Lex 。Yacc 和 Lex 来自 UNIX。Yacc 是 “yet another compiler compiler” 的缩写,而 Lex 则是 ‘lexical analyser’ 的简称。仅仅它们的名称就已经说明了很多问题 !你可以参阅 compilertools 站点 ,该站点提供了适合不同水平用户的范例,而且还有很详细的说明和解释。

>>> 阅读全文

 

, , , , ,