学习编译原理,写编译器(第一天)

学习编译原理,写编译器(第一天)

主要是学习词法分析器

目录

  • 1. 项目概述
  • 2. 正则表达式(Regular Expression)
  • 3. 如何安装 flex 以及小试身手

1. 项目概述

编译原理项目概述:

在2023年,我参与了一个编译原理项目,该项目的目标是创建一个简单的编译器,能够将C语言的测试程序编译成中间代码或可执行的汇编程序。这个项目涉及编译器的关键组成部分,包括词法分析、语法分析、中间代码生成、类型检查、代码优化、错误分析和汇编程序生成。

词法分析(Lexical Analysis):

词法分析是编译器的第一个阶段,其责任是分析源代码的结构,将源代码转换为有意义的词素(标记)。例如,在C程序中,标记可以是关键字如intwhile,标识符如变量名,符号如+*,以及数值字面量如123

语法分析(Syntax Analysis):

语法分析紧随词法分析,构建语法树以确保标记遵循语言的语法规则。语法树的节点表示源代码中的构造,例如,C中的if语句将形成语法树的一部分,包括其条件和主体。

中间代码生成(Intermediate Code Generation):

在这个阶段,编译器生成源代码的中间代码表示,通常以四元组等形式表示操作和操作数之间的关系。例如,将一个简单的算术表达式如a+b翻译成一系列中间指令。

类型检查和代码优化(Type Checking and Code Optimization):

类型检查涉及检查所使用的变量的类型,以确保它们以有效的方式进行操作。代码优化阶段会将中间代码转化为经过优化的代码,以提高运行效率。这可能包括删除不必要的代码行、优化循环等操作。

错误分析(Error Analysis):

错误分析阶段涉及识别和报告源代码中的任何错误,如语法错误或语义错误。这对于程序员在编写代码时提供反馈和修复问题非常重要。

汇编程序生成(Assembly Code Generation):

最后一个阶段是将优化后的中间代码转换为接近机器代码的汇编语言。这是为了将源代码最终编译成可执行程序。

项目实施与改进建议:

在实施项目时,我们使用了Flex、Bison、build-essential和NASM等工具,其中Flex用于定义词法分析规则,而Bison用于定义语法规则。项目实施过程需要一步一步地完成,并且可以根据需求进行改进,例如扩展支持实数数据类型、过程或函数调用、数组操作、指针操作和结构体。

重要概念:

在编译器项目中,我们还学到了一些重要的概念,其中包括符号表、文法、标记、关键字、标识符、运算符、常量等。这些概念在理解和实施编译器时起到了关键作用。

示例:

为了更好地理解这些概念,让我们来看一个示例。考虑下面的C代码片段:

int main() {
    int x = 10;
    int y = 20;
    int result = x + y;
    return result;
}

在这个代码片段中,词法分析会将其分解成标记,如intmainx=10y=20result=x+yreturnresult。语法分析会构建语法树,表示主函数、变量声明、赋值语句、加法表达式和返回语句之间的关系。中间代码生成阶段将加法表达式转换成中间代码,如四元组,表示加法操作。

2. 正则表达式(Regular Expression)

是一种用于匹配文本模式的强大工具。它在处理文本数据时非常有用,可以帮助你搜索、匹配和操作字符串,无论是在编程中还是在文本编辑器中都经常用到。现在让我详细解释一些正则表达式的基础知识,包括一些子知识点,并提供一个示例。

1. 什么是正则表达式?
正则表达式是一种文本模式,它定义了一种字符串的规则或模板。这些模板用于搜索、匹配、替换或验证字符串。正则表达式由一个或多个字符组成,这些字符表示特定的文本模式。

2. 基本字符和元字符:

  • 基本字符: 正则表达式中的大多数字符只是普通字符,它们代表自己。例如,字母、数字和常见的标点符号。
  • 元字符: 正则表达式中的元字符具有特殊含义,用于定义模式。例如,^ 表示字符串的开头,$ 表示字符串的结尾,. 表示任意字符,`` 表示前一个字符的零个或多个重复,+ 表示前一个字符的一个或多个重复,? 表示前一个字符的零个或一个重复。

3. 字符类和量词:

  • 字符类: 用方括号 [] 定义,表示在这个位置可以匹配多个字符中的任何一个。例如,[aeiou] 匹配任何一个元音字母。
  • 量词: 用来指定匹配字符或字符类的重复次数。例如,{n} 表示重复 n 次,{n,} 表示至少重复 n 次,{n,m} 表示重复 n 到 m 次。

4. 转义字符:
反斜杠 \\ 用来转义元字符,使其变成普通字符。例如,\\\\. 匹配实际的句点而不是任意字符。

5. 特殊字符类:
正则表达式中有一些预定义的特殊字符类,如 \\d 表示数字,\\w 表示单词字符(字母、数字、下划线),\\s 表示空白字符(空格、制表符等)。

6. 正则表达式示例:
假设你想匹配所有的电子邮件地址,正则表达式可以如下所示:

\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b

  • \\b 表示单词边界。
  • [A-Za-z0-9._%+-]+ 匹配电子邮件地址的用户名部分。
  • @ 匹配电子邮件地址中的 “@” 符号。
  • [A-Za-z0-9.-]+ 匹配域名部分。
  • \\. 匹配域名和顶级域名之间的句点。
  • [A-Za-z]{2,} 匹配顶级域名,至少要有两个字母。
  • \\b 再次表示单词边界。

这只是正则表达式的基础知识,正则表达式可以非常复杂,用于处理各种文本匹配和操作任务。如果你需要更多详细信息或示例,请随时提出。了解这些就够了,剩余的进行正则网站去实验。

3. 如何安装 flex 以及小试身手

以下是关于如何安装和配置 Flex 词法分析器的一些步骤:

1. 安装 Flex:

Flex 工具通常在 Unix/Linux 环境下使用,但也可以在 Windows 下使用。要在 Unix/Linux 上安装 Flex,你可以使用包管理器(如 apt、yum、brew 等)或者手动编译安装。

1.1在 Ubuntu/Debian 上,使用以下命令安装 Flex:

sudo apt-get install flex

1.2在 CentOS/RHEL 上,使用以下命令安装 Flex:

sudo yum install flex

1.3在 macOS 上安装和配置 Flex 词法分析器也很简单。以下是在 macOS 上安装和配置 Flex 的步骤:

a.安装 Xcode Command Line Tools:
a.如果你还没有安装 Xcode Command Line Tools(包括编译器和相关工具),请按照以下步骤安装:

  • 打开终端应用程序。
  • 运行以下命令来安装 Xcode Command Line Tools(如果尚未安装):
xcode-select --install

跟随安装过程中的提示完成安装。

b**. 安装 Homebrew(可选):**
Homebrew 是 macOS 上一个常用的包管理器,可以帮助你轻松安装各种开发工具,包括 Flex。如果你已经安装了 Homebrew,可以跳过这一步。如果尚未安装 Homebrew,请在终端中运行以下命令来安装:

/bin/bash -c "$(curl -fsSL <https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh>)"

c**. 安装 Flex:**
使用 Homebrew 或者直接使用系统自带的包管理器安装 Flex:
使用 Homebrew 安装:

brew install flex

或者,使用 macOS 自带的包管理器(不需要 Homebrew):

sudo port install flex

2**. 创建和编译 Flex 文件:**

让我们从一个简单的示例开始,编写一个基本的词法分析器,它可以识别整数、浮点数和标识符。我们将使用 Flex 来创建这个词法分析器。首先,创建一个名为 lexer.l 的 Flex 文件,并添加以下内容:

%{
#include 
%}

DIGIT [0-9]
LETTER [a-zA-Z]
ID {LETTER}({LETTER}|{DIGIT})*
INT {DIGIT}+
FLOAT {DIGIT}+"."{DIGIT}+

%%
{INT}    { printf("整数: %s\\n", yytext); }
{FLOAT}  { printf("浮点数: %s\\n", yytext); }
{ID}     { printf("标识符: %s\\n", yytext); }
.        { /* 忽略其他字符 */ }
%%

int main() {
    yylex();
    return 0;
}

上面的 Flex 文件定义了以下词法规则:

  • DIGIT:用于匹配数字。
  • LETTER:用于匹配字母。
  • ID:用于匹配标识符,它由字母开头,后跟零个或多个字母或数字。
  • INT:用于匹配整数,由一个或多个数字组成。
  • FLOAT:用于匹配浮点数,由数字、小数点和数字组成。
  • {} 中的规则是用来匹配输入文本中的标记,并输出相应的消息。

接下来,使用以下命令来编译 Flex 文件并生成词法分析器的可执行文件:

flex lexer.l
gcc -o lexer lex.yy.c -lfl

现在,你可以运行生成的词法分析器,并输入一些文本来测试它:

./lexer

随后,输入一些文本,例如:

1233.14variableName

词法分析器将会识别并输出相应的标记。

再来一个例子,熟悉一下

创建 Flex 词法规则文件:
接下来,你需要创建一个包含词法规则的 Flex 源文件。这个文件定义了如何将输入文本拆分成不同的词法单元(tokens)。通常,这个文件的扩展名为 .l。例如,下面是一个简单的 Flex 规则文件,用于识别简单的数字和标识符:

%{
#include 
%}

DIGIT [0-9]
ID [a-zA-Z][a-zA-Z0-9]*

%%
{DIGIT}+    { printf("Number: %s\\n", yytext); }
{ID}        { printf("Identifier: %s\\n", yytext); }
.           { /* 忽略其他字符 */ }
%%

int main() {
    yylex();
    return 0;
}

3. 编译 Flex 文件:
使用以下命令将 Flex 文件编译成词法分析器的 C 代码:

flex your_lex_file.l

这将生成一个名为 lex.yy.c 的 C 源文件。

4. 编译并运行词法分析器:
将生成的 lex.yy.c 文件编译为可执行文件:

gcc -o lexer lex.yy.c -lfl

然后,你可以运行生成的词法分析器并输入文本,它将识别并输出标记(tokens):

./lexer

这只是一个简单的示例,Flex 的词法规则非常灵活,你可以根据需要定义更复杂的规则来处理不同类型的输入。希望这些步骤能帮助你开始使用 Flex 词法分析器。

深入学习 Flex 的高级功能可以帮助你满足更复杂的词法分析需求。Flex 提供了一些强大的特性,如状态机、用户定义的词法状态、开始条件。我不做扩展,因为是做基础普及教育所以没必要。

flex:

你可能感兴趣的:(学习,汇编)