编译器----语法分析

本文通过学习王博俊、张宇的《DIY Compiler and Linker》 ,实现语法分析器,一方面作为自己的学习笔记,一方面也作与大家分享与交流

代码放在github上

一、语法分析的任务

语法分析任务是在词法分析识别出单词符号的基础上,分析源程序的语法结构,即分析由这些单词如何组成各种语法成分,比如“声明”、“函数”、“语句”、“表达式”等,并分析判断程序的语法结构是否复合语法规则。

语法分析分为自上而下和自下而上两个大类,自上而下核心思路是推导,自下而上核心思路是规约,本语法分析采用自上而下的方法。

在《编译原理》课上学到,自上而下方法需要避免左递归、消除回溯。自上而下分析方法分为两种:递归子程序法和预测分析方法,这里采用递归子程序法。

二、语法定义

在实现语法分析之前,先对语言的语法进行定义。

先列出巴科斯范式(EBNF)语法符号表,以防看不懂语法定义:

EBNF元符号 含义
::= 意思是“推导为”
|
{} 含0次在内任意多次重复
[] 含0次和1次重复
() 括号内看作一项
. 一条生成规则的结束
<> 非终结符
“” 终结符

2.1 外部定义

<翻译单元>::={
  <外部声明>}<文件结束符>

<外部声明>::=<函数定义>|<声明>
2.1.1 函数定义
<函数定义>::=<类型区分符><声明符><函数体>

<函数体>::=<复合语句>
2.1.2 声明
<声明>::=<类型区分符>[<初值声明符表>]<分号>

<初值声明符表>::=<初值声明符>{
  <逗号><初值声明符>}

<初值声明符>::=<声明符>|<声明符><赋值运算符><初值符>
2.1.3 类型区分符
<类型区分符>::=<void关键字>|<char关键字>|<short关键字>|<int关键字>|<结构区分符>

<结构区分符>::=<struct关键字><标识符><左大括号><结构声明表><右大括号>|<struct关键字><标识符>

<结构声明表>::=<结构声明>{
  <结构声明>}

<结构声明>::=<类型区分符>{
  <结构声明符表>}<分号>

<结构声明符表>::=<声明符>{
  <逗号><声明符>}
2.1.4 声明符
<声明符>::={
  <指针>}[<调用约定>][<结构体成员对齐>]<直接声明符>

<调用约定>::=<__cdecl关键字>|<__stdcall关键字>

<结构体成员对齐>::=<__align关键字><左小括号><整数常量><右小括号>

<指针>::=<星号>

<直接声明符>::=<标识符><直接声明符后缀>

<直接声明符后缀>::={
  <左中括号><右中括号>
    |<左中括号><整数常量><右中括号>
    |<左小括号><右小括号>
    |<左小括号><形参表><右小括号>}

<参数声明>::=<类型区分符><声明符>
2.1.5 初值符
<初值符>::=<赋值表达式>

2.2 语句

<语句>::={
  <复合语句>|
        <if语句>|
        <for语句>|
        <break语句>|
        <continue语句>|
        <return语句>|
        <表达式语句>}
2.2.1 复合语句
<复合语句>::=<左大括号>{
  <声明>}{
  <语句>}<右大括号>
2.2.2 表达式语句与空语句
<表达式语句>::=[<expression>]<分号>
2.2.3 选择语句
<if语句>::=<if关键字><左小括号><表达式><右小括号><语句>[<else关键字><语句>]
2.2.4 循环语句
<for语句>::=<for关键字><左小括号><表达式语句><表达式语句><表达式><右小括号><语句>
2.2.5 跳转语句
<continue语句>::=<continue关键字><分号>

<break语句>::=<break关键字><分号>

<return语句>::=<return关键字><expression><分号>

2.3 表达式

<表达式>::=<赋值表达式>{
  <逗号><赋值表达式>}
2.3.1 赋值表达式
<赋值表达式>::=<相等类表达式>|<一元表达式><赋值等号><赋值表达式>
2.3.2 相等类表达式
<相等类表达式>::=<关系表达式>{
  <等于号><关系表达式>|<不等于号><关系表达式>}
2.3.3 关系表达式
<关系表达式>::=<加减类表达式>{
            <小于号><加减类表达式>
            |<大于号><加减类表达式>
            |<小于等于号><加减类表达式>
            |<大于等于号><加减类表达式>}
2.3.4 加减类表达式
<加减类表达式>::=<乘除类表达式>{
            <加号><乘除类表达式>
            <减号><乘除类表达式>}
2.3.5 乘除类表达式
<乘除类表达式>::=<一元表达式>{
            <星号><一元表达式>
            |<除号><一元表达式>
            |<取余运算符><一元表达式>}
2.3.6 一元表达式
<一元表达式>::=<后缀表达式>
            |<与号><一元表达式>
            |<星号><一元表达式>
            |<加号><一元表达式>
            |<减号><一元表达式>
            |<sizeof表达式>

<sizeof表达式>::=<sizeof关键字>(<类型区分符>)
2.3.7 后缀表达式
<后缀表达式>::=<初等表达式>{
            <左中括号><expression><右中括号>
            |<左小括号><右小括号>
            |<左小括号><实参表达式表><右小括号>
            |<点号>IDENTIFIER
            |<箭头>IDENTIFIER}

<实参表达式表>::=<赋值表达式>{
  <逗号><赋值表达式>}
2.3.8 初等表达式
<初等表达式>::=<标识符>|<整数常量>|<字符串常量>|<字符常量>|(<表达式>)

三、语法分析的实现

为了将语法分析表示出来,我们给源代码进行语法缩进,来表示顺利实现语法分析

语法缩进由两个全局变量控制:

int syntax_state;  //语法状态
int syntax_level;  //缩进级别

语法状态取值为:

enum e_SynTaxState
{
    SNTX_NUL,       // 空状态,没有语法缩进动作
    SNTX_SP,        // 空格 int a; int __stdcall MessageBoxA(); return 1;
    SNTX_LF_HT,     // 换行并缩进,每一个声明、函数定义、语句结束都要置为此状态
    SNTX_DELAY      // 延迟取出下一单词后确定输出格式,取出下一个单词后,根据单词类型单独调用syntax_indent确定格式进行输出 
};

通过Tab键控制缩进级别:

void print_tab(int n)
{
    int i = 0;
    for (; i < n; i++)
        printf("\t");
}

语法缩进程序为:

void syntax_indent()
{
    switch (syntax_state)
    {
    case SNTX_NUL:
        color_token(LEX_NORMAL);
        break;
    case SNTX_SP:
        printf(" ");
        color_token(LEX_NORMAL);
        break;
    case SNTX_LF_HT:
    {
        if (token == TK_END)        // 遇到'}',缩进减少一级
            syntax_level--;
        printf("\n");
        print_tab(syntax_level);
    }
    color_token(LEX_NORMAL);
    break;
    case SNTX_DELAY:
        break;
    }
    syntax_state = SNTX_NUL;
}

不仅延续之间词法分析的词法着色,并且加上了语法缩进

每次在取单词时执行syntax_indent()函数

void get_token()
{
    ...
    syntax_indent();
}

3.1 外部定义语法分析

语法定义:

<翻译单元>::={
  <外部声明>}<文件结束符>
<外部声明>::=<函数定义>|<声明>

&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值