实验目的
- 学习,掌握递归下降分析法和抽象语法树的基本原理。
- 学习,掌握递归下降分析程序的构造方法。
实验原理
-
递归下降分析法的基本思想:
在不含有左递归的文法G中,为每个非终结符构造一个子程序,每个子程序的函数体按照非终结符的产生式分情况展开。遇到终结符则进行匹配,遇到非终结符则调用相应的非终结符的子程序。
-
递归下降分析法的前提:
改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法。 -
抽象语法树:
给定文法:G=(Vn,Vt,P,S),对于G的任何句型都能构造与之关联的语法树(推导树)。树中的每一个节点都有一个标记,此标记是V=Vn∪Vt中的一个符号。语法树是句子结构的图形表示,它代表了句子的推导结果,有利于理解句子语法结构的层次。
实验内容
- 学习所提供的表达式文法的递归下降处理:
(1)理解rdlex.l、rdparser.c的内容;
(2)在eclipse中建立工程并调试。 - 学习rdgram.txt所提供的文法,与词法分析所提供的文法作比较。
- 编写rdgram.text所提供文法的递归下降程序:
(1)编写不生成语法树的递归下降程序【rdcheck.c】;
(2)将rdcheck.c改造为生成语法树的递归下降程序【rdparser.c】;
(3)改进词法分析程序、showAst函数、main函数等,使递归下降程序rdparser.c最终从命令行读取要分析的程序test.c,分析后调用showAst打印该程序的结构。 - 所有文件都以utf-8进行统一编码保存。
实验器材
visual studio 2017
Notepad++,flex 2.5.4.1
实验步骤
一、学习rdgram.txt所提供的文法
举例:
program
: external_declaration
| program external_declaration
;
decl_or_stmt
: '{' statement_list '}'
| '{' '}'
| ',' declarator_list ';'
| ';'
;
提取左因子,消除左递归后如下:
program → external_declaration program_1
program_1 → external_declaration program_1 | ε
decl_or_stmt → { statement_list_1 } | declarator_list_2 ;
statement_list_1 → statement_list | ε
declarator_list_2 → , declarator_list | ε
二、编写不生成语法树的递归下降程序【rdcheck.c】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum yytokentype {
IF = 245,
ELSE = 246,
WHILE = 247,
RETURN = 248,
PRINT = 249,
SCAN = 250,
CMP = 251,
ASSIGN = 252,
INT = 253,
STR = 254,
VOID = 255,
STRING = 256,
ID = 257,
NUMBER = 258,
EOL = 259
};
extern int yylex();
extern int yylval;
extern char* yytext;
extern FILE* yyin;
void advance();
int program();
int program_1();
int external_declaration();
int decl_or_stmt();
int declarator_list();
int declarator_list_1();
int intstr_list();
int intstr_list_1();
int initializer();
int declarator();
int parameter_list();
int parameter_list_1();
int parameter();
int type();
int statement();
int statement_list();
int statement_list_1();
int expression_statement();
int expr();
int cmp_expr();
int cmp_expr_1();
int add_expr();
int add_expr_1();
int mul_expr();
int mul_expr_1();
int primary_expr();
int expr_list();
int expr_list_1();
int id_list();
int id_list_1();
int tok;
int main(int argc, char **argv)
{
printf("result:\n");
yyin = fopen("test.c", "r");
advance();
int r = program();
if (r == 1)
printf("True!\n\n");
else
printf("Fault!\n\n");
system("pause");
return 0;
}
void advance() {
tok = yylex();
printf("tok: %s\n", yytext);
}
//program
// : external_declaration
// | program external_declaration
// ;
int program() {
if (external_declaration())
if (program_1())
return 1;
return 0;
}
int program_1() {
if (external_declaration()) {
if (program_1())
return 1;
}
else
return 1;
return 0;
}
//external_declaration
// : type declarator decl_or_stmt
// ;
int external_declaration() {
if (type())
if (declarator())
if (decl_or_stmt())
return 1;
return 0;
}
//decl_or_stmt
// : '{' statement_list '}'
// | '{' '}'
// | ',' declarator_list ';'
// | ';'
// ;
int decl_or_stmt() {
if (tok == '{') {
advance();
if (statement_list())
;
if (tok == '}') {
advance();
return 1;
}
}
else if (tok == ',') {
advance();
if (declarator_list())
if (tok == ';') {
advance();
return 1;
}
}
else if (tok == ';') {
advance();
return 1;
}
return 0;
}
//declarator_list
// : declarator
// | declarator_list ',' declarator
// ;
int declarator_list() {
if (declarator())
if (declarator_list_1())
return 1;
return 0;
}
int declarator_list_1() {
if (tok == ',') {
advance();
if (declarator())
if (declarator_list_1())
return 1;
}
else
return 1;
return 0;
}
//intstr_list
// : initializer
// | intstr_list ',' initializer
// ;
int intstr_list() {
if (initializer())
if (intstr_list_1())
return 1;
return 0;
}
int intstr_list_1() {
if (tok == ',') {
advance();
if (initializer())
if (intstr_list_1())
return 1;
}
else
return 1;
return 0;
}
//initializer
// : NUMBER
// | STRING
// ;
int initializer() {
if (tok == NUMBER) {
advance();
return 1;
}
else if (tok == STRING) {
advance();
return 1;
}
return 0;
}
//declarator
// : ID
// | ID '=' expr
// | ID '(' parameter_list ')'
// | ID '(' ')'
// | ID '[' expr ']'
// | ID '[' ']'
// | ID '[' expr ']' '=' '{' intstr_list '}'
// | ID '[' ']' '=' '{' intstr_list '}'
// ;
int declarator() {
if (tok == ID) {
advance();
if (tok == '=') {
advance();
if (expr())
return 1;
}
else if (tok == '(') {
advance();
if (parameter_list())
;
if (tok == ')') {
advance();
return 1;
}
}
else if (tok == '[') {
advance();
if (expr())
;
if (tok == ']') {
advance();
if (tok == '=') {
advance();
if (tok == '{') {
advance();
if (intstr_list())
if (tok == '}') {
advance();
return 1;
}
}
return 0;
}
return 1;
}
}
return 1;
}
return 0;
}
//parameter_list
// : parameter
// | parameter_list ',' parameter
// ;
int parameter_list() {
if (parameter())
if (parameter_list_1())
return 1;
return 0;
}
int parameter_list_1() {
if (tok == ',') {
advance();
if (parameter())
if (parameter_list_1())
return 1;
}
else
return 1;
return 0;
}
//parameter
// : type ID
// ;
int parameter() {
if (type())
if (tok == ID) {
advance();
return 1;
}
return 0;
}
//type
// : INT
// | STR
// | VOID
// ;
int type() {
if (tok == INT) {
advance();
return 1;
}
else if (tok == STR) {
advance();
return 1;
}
else if (tok == VOID) {
advance();
return 1;
}
return 0;
}
//statement
// : type declarator_list ';'
// | '{' statement_list '}'
// | expr_statement //⬅这个是不是有问题?先改成expression_statement
// | IF '(' expr ')' statement
// | IF '(' expr ')' statement ELSE statement
// | WHILE '(' expr ')' statement
// | RETURN ';'
// | RETURN expr ';'
// | PRINT ';'
// | PRINT expr_list ';'
// | SCAN id_list ';'
// ;
int statement() {
if (type()) {
if (declarator_list())
if (tok == ';') {
advance();
return 1;
}
}
else if (tok == '{') {
advance();
if (statement_list())
if (tok == '}') {
advance();
return 1;
}
}
else if (expression_statement())
return 1;
else if (tok == IF) {
advance();
if (tok == '(') {
advance();
if (expr())
if (tok == ')') {
advance();
if (statement()) {
if (tok == ELSE) {
advance();
if (statement())
return 1;
}
else
return 1;
}
}
}
}
else if (tok == WHILE) {
advance();
if (tok == '(') {
advance();
if (expr())
if (tok == ')') {
advance();
if (statement())
return 1;
}
}
}
else if (tok == RETURN) {
advance();
if (expr())
;
if (tok == ';') {
advance();
return 1;
}
}
else if (tok == PRINT) {
advance();
if (expr_list())
;
if (tok == ';') {
advance();
return 1;
}
}
else if (tok == SCAN) {
advance();
if (id_list())
if (tok == ';') {
advance();
return 1;
}
}
return 0;
}
//statement_list
// : statement
// | statement_list statement
// ;
int statement_list() {
if (statement())
if (statement_list_1())
return 1;
return 0;
}
int statement_list_1() {
if (statement()) {
if (statement_list_1())
return 1;
}
else
return 1;
return 0;
}
//expression_statement
// : ';'
// | expr ';'
// ;
int expression_statement() {
if (tok == ';') {
advance();
return 1;
}
else if (expr())
if (tok == ';') {
advance();
return 1;
}
return 0;
}
//expr
// : cmp_expr
// ;
int expr() {
if (cmp_expr())
return 1;
return 0;
}
//cmp_expr
// : add_expr
// | cmp_expr CMP add_expr
// ;
int cmp_expr() {
if (add_expr())
if (cmp_expr_1())
return 1;
return 0;
}
int cmp_expr_1() {
if (tok == CMP) {
advance();
if (add_expr())
if (cmp_expr_1())
return 1;
}
else
return 1;
return 0;
}
//add_expr
// : mul_expr
// | add_expr '+' mul_expr
// | add_expr '-' mul_expr
// ;
int add_expr() {
if (mul_expr())
if (add_expr_1())
return 1;
return 0;
}
int add_expr_1() {
if (tok == '+' || tok == '-') {
advance();
if (mul_expr())
if (add_expr_1())
return 1;
}
else
return 1;
return 0;
}
//mul_expr
// : primary_expr
// | mul_expr '*' primary_expr
// | mul_expr '/' primary_expr
// | mul_expr '%' primary_expr
// | '-' primary_expr
// ;
int mul_expr() {
if (tok == '-')
advance();
if (primary_expr())
if (mul_expr_1())
return 1;
return 0;
}
int mul_expr_1() {
if (tok == '*' || tok == '/' || tok == '%') {
advance();
if (primary_expr())
if (mul_expr_1())
return 1;
}
else
return 1;
return 0;
}
//primary_expr
// : ID '(' expr_list ')'
// | ID '(' ')'
// | '(' expr ')'
// | ID
// | NUMBER
// | STRING
// | ID ASSIGN expr
// | ID '=' expr
// | ID '[' expr ']'
// | ID '[' expr ']' '=' expr
// ;
int primary_expr() {
if (tok == ID) {
advance();
if (tok == '(') {
advance();
if (expr_list())
;
if (tok == ')') {
advance();
return 1;
}
}
else if (tok == ASSIGN) {
advance();
if (expr())
return 1;
}
else if (tok == '=') {
advance();
if (expr())
return 1;
}
else if (tok == '[') {
advance();
if (expr())
if (tok == ']') {
advance();
if (tok == '=') {
advance();
if (expr())
return 1;
else
return 0;
}
return 1;
}
}
else
return 1;
}
else if (tok == '(') {
advance();
if (expr())
if (tok == ')') {
advance();
return 1;
}
}
else if (tok == NUMBER) {
advance();
return 1;
}
else if (tok == STRING) {
advance();
return 1;
}
return 0;
}
//expr_list
// : expr
// | expr_list ',' expr
// ;
int expr_list() {
if (expr())
if (expr_list_1())
return 1;
return 0;
}
int expr_list_1() {
if (tok == ',') {
advance();
if (expr())
if (expr_list_1())
return 1;
}
else
return 1;
return 0;
}
//id_list
// : ID
// | id_list ',' ID
// ;
int id_list() {
if (tok == ID) {
advance();
if (id_list_1())
return 1;
}
return 0;
}
int id_list_1() {
if (tok == ',') {
advance();
if (tok == ID) {
advance();
if (id_list_1())
return 1;
}
}
else
return 1;
return 0;
}
三、将rdcheck.c改造为生成语法树的递归下降程序【rdparser.c】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum TokenType {
IF = 245,
ELSE = 246,
WHILE = 247,
RETURN = 248,
PRINT = 249,
SCAN = 250,
CMP = 251,
ASSIGN = 252,
INT = 253,
STR = 254,
VOID = 255,
STRING = 256,
ID = 257,
NUMBER = 258,
EOL = 259
};
extern int yylex();
extern int yylval;
extern char* yytext;
extern FILE* yyin;
typedef struct _ast ast;
typedef struct _ast *past;
struct _ast {
char *nodeType; //类型
char *content; //内容
past left; //左分支
past right; //右分支
};
int tok;
void advance();
past program();
past external_declaration();
past decl_or_stmt();
past declarator_list();
past intstr_list();
past initializer();
past declarator();
past parameter_list();
past parameter();
past type();
past statement();
past statement_list();
past expression_statement();
past expr();
past cmp_expr();
past add_expr();
past mul_expr();
past primary_expr();
past expr_list();
past id_list();
past newAstNode(char *nodeType, char *content, past left, past right);
void showAst(past node, int nest);
void freeAst(past node);
int main(int argc, char **argv)
{
printf("result:\n");
yyin = fopen("test.c", "r");
advance();
past root = program();
printf("");
showAst(root, 0);
freeAst(root);
system("pause");
return 0;
}
void advance() {
tok = yylex();
printf("tok: %s\n", yytext);
}
//构造新结点
past newAstNode(char *nodeType, char *content, past left, past right) {
past node = (past)malloc(sizeof(ast));
if (node == NULL) {
printf("run out of memory.\n");
exit(0);
}
node->nodeType = nodeType;
node->content = content;
node->left = left;
node->right = right;
return node;
}
//输出语法树
void showAst(past node, int nest) {
if (node == NULL)
return;
int i = 0;
for (i = 0; i < nest; i++)
printf(" ");
printf("%s: %s\n", node->nodeType, node->content);
showAst(node->left, nest + 1);
showAst(node->right, nest + 1);
}
//释放结点
void freeAst(past node) {
if (node == NULL)
return;
freeAst(node->left);
freeAst(node->right);
free(node);
}
//program
// : external_declaration
// | program external_declaration
// ;
past program() {
past root = NULL;
if (root = external_declaration())
root = newAstNode("program", "", root, program());
return root;
}
//external_declaration
// : type declarator decl_or_stmt
// ;
past external_declaration() {
past root = NULL;
if (root = type()) {
root = newAstNode("external_declaration", "", root, newAstNode("typebody", "", NULL, NULL));
if (root->right->left = declarator())
if (root->right->right = decl_or_stmt())
;
}
return root;
}
//decl_or_stmt
// : '{' statement_list '}'
// | '{' '}'
// | ',' declarator_list ';'
// | ';'
// ;
past decl_or_stmt() {
past root = NULL;
if (tok == '{') {
advance();
if (root = statement_list())
root = newAstNode("decl_or_stmt", "", root, NULL);
if (tok == '}')
advance();
}
else if (tok == ',') {
advance();
if (root = declarator_list())
if (tok == ';')
advance();
}
else if (tok == ';')
advance();
return root;
}
//declarator_list
// : declarator
// | declarator_list ',' declarator
// ;
past declarator_list() {
past root = NULL;
if (root = declarator()) {
root = newAstNode("declarator_list", "", root, NULL);
if (tok == ',') {
advance();
root->right = declarator_list();
}
}
return root;
}
//intstr_list
// : initializer
// | intstr_list ',' initializer
// ;
past intstr_list() {
past root = NULL;
if (root = initializer()) {
root = newAstNode("intstr_list", "", root, NULL);
if (tok == ',') {
advance();
root->right = intstr_list();
}
}
return root;
}
//initializer
// : NUMBER
// | STRING
// ;
past initializer() {
past root = NULL;
if (tok == NUMBER) {
root = newAstNode("number", strdup(yytext), NULL, NULL);
advance();
}
else if (tok == STRING) {
root = newAstNode("string", strdup(yytext), NULL, NULL);
advance();
}
return root;
}
//declarator
// : ID
// | ID '=' expr
// | ID '(' parameter_list ')'
// | ID '(' ')'
// | ID '[' expr ']'
// | ID '[' ']'
// | ID '[' expr ']' '=' '{' intstr_list '}'
// | ID '[' ']' '=' '{' intstr_list '}'
// ;
past declarator() {
past root = NULL;
if (tok == ID) {
root = newAstNode("declarator", strdup(yytext), NULL, NULL);
advance();
if (tok == '=') {
advance();
root->right = expr();
}
else if (tok == '(') {
advance();
root->left = parameter_list();
if (tok == ')')
advance();
}
else if (tok == '[') {
advance();
root->left = expr();
if (tok == ']') {
advance();
if (tok == '=') {
advance();
if (tok == '{') {
advance();
if (root->right = intstr_list()) {
root->right = newAstNode("InitListExpr", "", root->right, NULL);
if (tok == '}')
advance();
}
}
}
}
}
}
return root;
}
//parameter_list
// : parameter
// | parameter_list ',' parameter
// ;
past parameter_list() {
past root = NULL;
if (root = parameter()) {
root = newAstNode("parameter_list", "", root, NULL);
if (tok == ',') {
advance();
root->right = parameter_list();
}
}
return root;
}
//parameter
// : type ID
// ;
past parameter() {
past root = NULL;
if (root = type())
if (tok == ID) {
root = newAstNode("parameter", "", root, newAstNode("ID", strdup(yytext), NULL, NULL));
advance();
}
return root;
}
//type
// : INT
// | STR
// | VOID
// ;
past type() {
past root = NULL;
if (tok == INT || tok == STR || tok == VOID) {
root = newAstNode("type", strdup(yytext), NULL, NULL);
advance();
}
return root;
}
//statement
// : type declarator_list ';'
// | '{' statement_list '}'
// | expr_statement //⬅这个是不是有问题?先改成expression_statement
// | IF '(' expr ')' statement
// | IF '(' expr ')' statement ELSE statement
// | WHILE '(' expr ')' statement
// | RETURN ';'
// | RETURN expr ';'
// | PRINT ';'
// | PRINT expr_list ';'
// | SCAN id_list ';'
// ;
past statement() {
past root = NULL;
if (root = type()) {
root = newAstNode("declarator_statement", "", root, NULL);
if (root->right = declarator_list())
if (tok == ';')
advance();
}
else if (tok == '{') {
advance();
if (root = statement_list()) {
root = newAstNode("compound_statement", "", root, NULL);
if (tok == '}')
advance();
}
}
else if (root = expression_statement())
;
else if (tok == IF) {
root = newAstNode("if_statement", "", NULL, newAstNode("ifbody", "", NULL, NULL));
advance();
if (tok == '(') {
advance();
if (root->left = expr())
if (tok == ')') {
advance();
if (root->right->left = statement())
if (tok == ELSE) {
advance();
if (root->right->right = statement())
;
}
}
}
}
else if (tok == WHILE) {
root = newAstNode("while_statement", "", NULL, NULL);
advance();
if (tok == '(') {
advance();
if (root->left = expr())
if (tok == ')') {
advance();
if (root->right = statement())
;
}
}
}
else if (tok == RETURN) {
root = newAstNode("return_statement", "", NULL, NULL);
advance();
root->left = expr();
if (tok == ';')
advance();
}
else if (tok == PRINT) {
root = newAstNode("print_statement", "", NULL, NULL);
advance();
root->left = expr_list();
if (tok == ';')
advance();
}
else if (tok == SCAN) {
root = newAstNode("scan_statement", "", NULL, NULL);
advance();
if (root->left = id_list())
if (tok == ';')
advance();
}
return root;
}
//statement_list
// : statement
// | statement_list statement
// ;
past statement_list() {
past right = statement();
if (right == NULL)
return NULL;
else
return newAstNode("statement_list", "", statement_list(), right);
}
//expression_statement
// : ';'
// | expr ';'
// ;
past expression_statement() {
past root = NULL;
if (tok == ';')
advance();
else if (root = expr()) {
if (tok == ';')
advance();
}
return root;
}
//expr
// : cmp_expr
// ;
past expr() {
return cmp_expr();
}
//cmp_expr
// : add_expr
// | cmp_expr CMP add_expr
// ;
past cmp_expr() {
past root = NULL;
root = add_expr();
if (root)
while (tok==CMP) {
root = newAstNode("cmp_expr", strdup(yytext), root, NULL);
advance();
root->right = add_expr();
}
return root;
}
//add_expr
// : mul_expr
// | add_expr '+' mul_expr
// | add_expr '-' mul_expr
// ;
past add_expr() {
past root = NULL;
root = mul_expr();
if (root)
while (tok == '+' || tok == '-') {
root = newAstNode("add_expr", strdup(yytext), root, NULL);
advance();
root->right = mul_expr();
}
return root;
}
//mul_expr
// : primary_expr
// | mul_expr '*' primary_expr
// | mul_expr '/' primary_expr
// | mul_expr '%' primary_expr
// | '-' primary_expr
// ;
past mul_expr() {
past root = NULL;
root = primary_expr();
if (root) {
while (tok == '*' || tok == '/' || tok == '%') {
root = newAstNode("mul_expr", strdup(yytext), root, NULL);
advance();
root->right = primary_expr();
}
}
else if (tok == '-') {
root = newAstNode("mul_expr", strdup(yytext), NULL, NULL);
advance();
root->right = primary_expr();
}
return root;
}
//primary_expr
// : ID '(' expr_list ')'
// | ID '(' ')'
// | '(' expr ')'
// | ID
// | NUMBER
// | STRING
// | ID ASSIGN expr
// | ID '=' expr
// | ID '[' expr ']'
// | ID '[' expr ']' '=' expr
// ;
past primary_expr() {
past root = NULL;
if (tok == ID) {
root = newAstNode("primary_expr", strdup(yytext), NULL, NULL);
advance();
if (tok == '(') {
advance();
root->left = expr_list();
if (tok == ')')
advance();
}
else if (tok == '[') {
advance();
if (root->left = expr())
if (tok == ']') {
advance();
if (tok == '=') {
root = newAstNode("Operator", strdup(yytext), root, NULL);
advance();
root->right = expr();
}
}
}
else if (tok == '=' || tok == ASSIGN) {
root = newAstNode("primary_expr", strdup(yytext), root, NULL);
advance();
root->right = expr();
}
}
else if (tok == '(') {
advance();
if (root = expr())
if (tok == ')')
advance();
}
else if (tok == NUMBER) {
root = newAstNode("number", strdup(yytext), NULL, NULL);
advance();
}
else if (tok == STRING) {
root = newAstNode("string", strdup(yytext), NULL, NULL);
advance();
}
return root;
}
//expr_list
// : expr
// | expr_list ',' expr
// ;
past expr_list() {
past root = NULL;
if (root = expr()) {
root = newAstNode("expr_list", "", root, NULL);
if (tok == ',') {
advance();
root->right = expr_list();
}
}
return root;
}
//id_list
// : ID
// | id_list ',' ID
// ;
past id_list() {
past root = NULL;
if (tok == ID) {
root = newAstNode("id_list", NULL, newAstNode("ID", strdup(yytext), NULL, NULL), NULL);
advance();
if (tok == ',') {
advance();
root->right = id_list();
}
}
return root;
}
四、改进词法分析程序c14_lex.l、showAst函数、main函数等,使递归下降程序rdparser.c最终从命令行读取要分析的程序test.c,分析后调用showAst打印该程序的结构。
%{
enum yytokentype {
IF = 245,
ELSE = 246,
WHILE = 247,
RETURN = 248,
PRINT = 249,
SCAN = 250,
CMP = 251,
ASSIGN = 252,
INT = 253,
STR = 254,
VOID = 255,
STRING = 256,
ID = 257,
NUMBER = 258,
EOL = 259
};
int yylval;
%}
NOTE [^\n]*
STRING [^"]*
%%
"//"{NOTE} { /* ignore note */ }
["][^"]*["] { yylval = atoi(yytext); return STRING; }
"int" { yylval = atoi(yytext); return INT; }
"str" { yylval = atoi(yytext); return STR; }
"void" { yylval = atoi(yytext); return VOID; }
"if" { yylval = atoi(yytext); return IF; }
"else" { yylval = atoi(yytext); return ELSE; }
"while" { yylval = atoi(yytext); return WHILE; }
"return" { yylval = atoi(yytext); return RETURN; }
"print" { yylval = atoi(yytext); return PRINT; }
"scan" { yylval = atoi(yytext); return SCAN; }
"assign" { yylval = atoi(yytext); return ASSIGN; }
"+"|"-"|"*"|"/"|"%"|"=" { return yytext[0]; }
"("|")"|"["|"]"|"{"|"}" { return yytext[0]; }
","|";" { return yytext[0]; }
">"|"<"|"<="|">="|"==" { yylval = atoi(yytext); return CMP; }
[a-z][a-zA-Z0-9|_]* { yylval = atoi(yytext); return ID; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
[ \t] { /* ignore whitespace */ }
. { printf("Mystery character %c\n", *yytext); }
%%
int yyerror(char *s)
{
fprintf(stderr, "error: %s\n", s);
return 0;
}
int yywrap()
{
return 1;
}
实验结果
一、不生成语法树的递归下降程序【rdcheck.c】
二、生成语法树的递归下降程序【rdparser.c】
编译技术实验: