如何使用Bison、Flex完成一个语法解析程序

背景

我想要编写一个类似awk的程序。用于文本行的处理。基本程序流程框架确定了以后,我遇到了一个语法解析的问题。这看起来没有那么容易。所以想要借鉴一下现有的工具。这时就发现了bison、flex。事实上,早有耳闻但是从未实际的上手。

参考资料

Bison 3.8.1

Bison 3.8.1

http://alumni.cs.ucr.edu/~jiayu/152spring/java.y

实践

使用Bison、flex创建语法解析程序可以有如下几个步骤:

首先是安装这个工具

yum install bison flex
zypper in bison flex
brew install bison flex

 上面是几个流行操作系统的安装命令。

程序代码

ast.h

#ifndef AST_H
#define AST_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct ASTNode {
    char *type;
} ASTNode;

ASTNode *createNode(const char *type);
void freeNode(ASTNode *node);

#endif // AST_H

calc.y

%{
#include "ast.h"
void yyerror(const char *s) {
    fprintf(stderr, "Error: %s\n", s);
}
int yylex(void);
%}

%union {
    ASTNode *node;
}

%token <node> NUMBER
%type <node> expr

%left '+'

%%

expr:
    NUMBER {
        $$ = $1; // NUMBER 已经是 ASTNode* 类型
    }
    | expr '+' expr {
        $$ = createNode("add");
    }
;

%%

ASTNode *createNode(const char *type) {
    ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode));
    node->type = strdup(type);
    return node;
}

void freeNode(ASTNode *node) {
    if (node) {
        free(node->type);
        free(node);
    }
}

int main(int argc, char **argv) {
    yyparse();
    return 0;
}

calc.l

%{
#include "ast.h"
#include "calc.tab.h"
%}

%%

[0-9]+ {
    yylval.node = createNode("number");
    return NUMBER;
}

\+ {
    return '+';
}
\- {
    return '-';
}

\n { /* 忽略换行 */ }

. { /* 忽略其他字符 */ }

%%

程序的编译

程序的编译流程如下:

#!/bin/bash

bison -d calc.y       # 生成 calc.tab.c 和 calc.tab.h
flex calc.l           # 生成 lex.yy.c
os_type=$(uname)

case "$os_type" in
    "Darwin")
        # macOS 专有的操作
        echo "Running on macOS"
        # 在这里添加macOS专有的命令
        # libfl-static include the static library that include main() and yywrap();
        # https://stackoverflow.com/questions/26064096/using-flex-the-lexical-analizer-on-os-x
        gcc -o calc lex.yy.c calc.tab.c -ll # 编译生成的 C 文件
        ;;
    "Linux")
        # Linux 专有的操作
        echo "Running on Linux"
        # 在这里添加Linux专有的命令
        gcc -o calc lex.yy.c calc.tab.c -lfl # 编译生成的 C 文件
        ;;
    *)
        # 其他操作系统
        echo "Unknown OS: $os_type"
        ;;
esac
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值