用c++写一个完整的语法分析器
时间: 2023-12-04 20:02:30 浏览: 75
语法分析器是编译器的一个重要组成部分,用来将源代码转化为抽象语法树(AST)。
以下是一个简单的用C++编写语法分析器的例子:
1. 定义词法分析器
词法分析器负责将源代码转化为一系列令牌(token)。每个令牌代表一个语法元素(如关键字、标识符、运算符等),并且包含了该元素的类型和值。
在这个例子中,我们使用flex生成词法分析器的代码:
```c++
%{
#include "parser.h"
%}
%%
[ \t\n] /* 忽略空格、制表符和换行符 */
int { yylval.i = atoi(yytext); return T_INT; }
float { yylval.f = atof(yytext); return T_FLOAT; }
"if" { return T_IF; }
"else" { return T_ELSE; }
"while" { return T_WHILE; }
"for" { return T_FOR; }
"(" { return T_LPAREN; }
")" { return T_RPAREN; }
"{" { return T_LBRACE; }
"}" { return T_RBRACE; }
";" { return T_SEMICOLON; }
[+\-*/] { return *yytext; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval.s = strdup(yytext); return T_IDENT; }
[0-9]+\.[0-9]* { yylval.f = atof(yytext); return T_FLOAT; }
[0-9]+ { yylval.i = atoi(yytext); return T_INT; }
. { return yytext[0]; }
%%
int yywrap() {
return 1;
}
```
2. 定义语法规则
语法规则定义了编程语言的语法结构,并且规定了如何将令牌序列转化为抽象语法树。
在这个例子中,我们使用bison生成语法分析器的代码:
```c++
%{
#include "parser.h"
#include <iostream>
using namespace std;
void yyerror(const char *msg) {
cerr << msg << endl;
}
%}
%union {
int i;
float f;
char *s;
}
%token <i> T_INT
%token <f> T_FLOAT
%token <s> T_IDENT
%token T_IF T_ELSE T_WHILE T_FOR
%token T_LPAREN T_RPAREN T_LBRACE T_RBRACE T_SEMICOLON
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%%
program:
stmt_list { cout << "parse success" << endl; }
;
stmt_list:
stmt { cout << "stmt_list" << endl; }
| stmt_list stmt { cout << "stmt_list" << endl; }
;
stmt:
expr_stmt { cout << "stmt" << endl; }
| compound_stmt { cout << "stmt" << endl; }
| selection_stmt { cout << "stmt" << endl; }
| iteration_stmt { cout << "stmt" << endl; }
;
expr_stmt:
expr ';' { cout << "expr_stmt" << endl; }
| ';' { cout << "expr_stmt" << endl; }
;
compound_stmt:
'{' stmt_list '}' { cout << "compound_stmt" << endl; }
;
selection_stmt:
T_IF '(' expr ')' stmt { cout << "selection_stmt" << endl; }
| T_IF '(' expr ')' stmt T_ELSE stmt { cout << "selection_stmt" << endl; }
;
iteration_stmt:
T_WHILE '(' expr ')' stmt { cout << "iteration_stmt" << endl; }
| T_FOR '(' expr_stmt expr_stmt expr ')' stmt { cout << "iteration_stmt" << endl; }
;
expr:
T_IDENT '=' expr { cout << "expr" << endl; }
| simple_expr { cout << "expr" << endl; }
;
simple_expr:
term { cout << "simple_expr" << endl; }
| simple_expr '+' term { cout << "simple_expr" << endl; }
| simple_expr '-' term { cout << "simple_expr" << endl; }
;
term:
factor { cout << "term" << endl; }
| term '*' factor { cout << "term" << endl; }
| term '/' factor { cout << "term" << endl; }
;
factor:
T_IDENT { cout << "factor" << endl; }
| T_INT { cout << "factor" << endl; }
| T_FLOAT { cout << "factor" << endl; }
| '-' factor %prec UMINUS { cout << "factor" << endl; }
| '(' expr ')' { cout << "factor" << endl; }
;
%%
int main() {
return yyparse();
}
```
3. 定义头文件
为了让词法分析器和语法分析器能够互相调用,我们需要定义一个头文件:
```c++
#ifndef PARSER_H
#define PARSER_H
#include <cstdlib>
#include <cstdio>
#include <cstring>
extern int yyparse();
extern int yylex();
extern int yyerror(const char *msg);
#endif /* PARSER_H */
```
4. 编译生成语法分析器
使用以下命令编译生成语法分析器:
```bash
bison -d parser.y
```
这个命令将生成parser.tab.c和parser.tab.h两个文件。
5. 编译生成词法分析器
使用以下命令编译生成词法分析器:
```bash
flex -o lexer.cpp lexer.l
```
这个命令将生成lexer.cpp文件。
6. 编译链接生成可执行文件
使用以下命令编译链接生成可执行文件:
```bash
g++ -o parser parser.tab.c lexer.cpp -ll
```
7. 测试
输入源代码:
```c++
int main() {
int a = 1;
float b = 2.0;
if (a > b) {
a = a + 1;
} else {
b = b * 2.0;
}
while (a < 10) {
a = a + 1;
}
for (int i = 0; i < 10; i = i + 1) {
b = b / 2.0;
}
return 0;
}
```
运行可执行文件,输出:
```
parse success
```
阅读全文