【问题标题】:How to write yacc grammar rules to identify function definitions vs function calls?如何编写 yacc 语法规则来识别函数定义与函数调用?
【发布时间】:2017-07-19 09:14:31
【问题描述】:

我已经开始学习YACC,并且我已经执行了一些简单的玩具程序示例。但是我从来没有见过一个实际的例子来演示如何构建一个编译器来识别和实现函数定义函数调用数组实现等等上,也不容易找到使用谷歌搜索的例子。有人可以提供一个如何使用 YACC 生成树的示例吗? C 或 C++ 都可以。

提前致谢!

【问题讨论】:

  • ANSI C Yacc grammar 怎么样?这个声明的东西让我发疯,直到我终于能够掌握它。 (我使用这个语法作为“模板”来“手动”编写递归下降解析器。)
  • 我相信这对于其他命令式语言来说要容易得多,例如Pascal.
  • 我在 C. Fraser 和 D. Hanson 的“A Retargetable C Compiler - Design and Implementation”中找到了关于这个“声明内容”的最终启示。当然,任何编译器构造主题的一般来源都是dragon books
  • @Scheff 这是我需要的语法,而不是 AST。不过感谢您提供的资源。

标签: flex-lexer yacc lex


【解决方案1】:

让我们用 yacc 解析这段代码。

文件 test 包含我们要解析的有效 C 代码。

int main (int c, int b) {
    int a;
    while ( 1 ) {

    int d;
}
}

一个 lex 文件 c.l

alpha [a-zA-Z]
digit [0-9]

%%
[ \t]       ;
[ \n]   { yylineno = yylineno + 1;}
int return INT;
float return FLOAT;
char return CHAR;
void return VOID;
double return DOUBLE;
for     return FOR;
while   return WHILE;
if  return IF;
else    return ELSE;
printf  return PRINTF;
struct  return STRUCT;
^"#include ".+ ;
{digit}+       return NUM;
{alpha}({alpha}|{digit})* return ID;
"<="    return LE;
">="    return GE;
"=="    return EQ;
"!="    return NE;
">" return GT;
"<" return LT;
"."     return DOT;
\/\/.* ;
\/\*(.*\n)*.*\*\/ ;
.       return yytext[0];
%%

文件 c.y 用于输入到 YACC:

%{
#include <stdio.h>
#include <stdlib.h>

extern FILE *fp;

%}

%token INT FLOAT CHAR DOUBLE VOID
%token FOR WHILE
%token IF ELSE PRINTF
%token STRUCT
%token NUM ID
%token INCLUDE
%token DOT

%right '='
%left AND OR
%left '<' '>' LE GE EQ NE LT GT
%%

start:  Function
    | Declaration
    ;

/* Declaration block */
Declaration: Type Assignment ';'
    | Assignment ';'
    | FunctionCall ';'
    | ArrayUsage ';'
    | Type ArrayUsage ';'
    | StructStmt ';'
    | error
    ;

/* Assignment block */
Assignment: ID '=' Assignment
    | ID '=' FunctionCall
    | ID '=' ArrayUsage
    | ArrayUsage '=' Assignment
    | ID ',' Assignment
    | NUM ',' Assignment
    | ID '+' Assignment
    | ID '-' Assignment
    | ID '*' Assignment
    | ID '/' Assignment
    | NUM '+' Assignment
    | NUM '-' Assignment
    | NUM '*' Assignment
    | NUM '/' Assignment
    | '\'' Assignment '\''
    | '(' Assignment ')'
    | '-' '(' Assignment ')'
    | '-' NUM
    | '-' ID
    |   NUM
    |   ID
    ;

/* Function Call Block */
FunctionCall : ID'('')'
    | ID'('Assignment')'
    ;

/* Array Usage */
ArrayUsage : ID'['Assignment']'
    ;

/* Function block */
Function: Type ID '(' ArgListOpt ')' CompoundStmt
    ;
ArgListOpt: ArgList
    |
    ;
ArgList:  ArgList ',' Arg
    | Arg
    ;
Arg:    Type ID
    ;
CompoundStmt:   '{' StmtList '}'
    ;
StmtList:   StmtList Stmt
    |
    ;
Stmt:   WhileStmt
    | Declaration
    | ForStmt
    | IfStmt
    | PrintFunc
    | ';'
    ;

/* Type Identifier block */
Type:   INT
    | FLOAT
    | CHAR
    | DOUBLE
    | VOID
    ;

/* Loop Blocks */
WhileStmt: WHILE '(' Expr ')' Stmt
    | WHILE '(' Expr ')' CompoundStmt
    ;

/* For Block */
ForStmt: FOR '(' Expr ';' Expr ';' Expr ')' Stmt
       | FOR '(' Expr ';' Expr ';' Expr ')' CompoundStmt
       | FOR '(' Expr ')' Stmt
       | FOR '(' Expr ')' CompoundStmt
    ;

/* IfStmt Block */
IfStmt : IF '(' Expr ')'
        Stmt
    ;

/* Struct Statement */
StructStmt : STRUCT ID '{' Type Assignment '}'
    ;

/* Print Function */
PrintFunc : PRINTF '(' Expr ')' ';'
    ;

/*Expression Block*/
Expr:
    | Expr LE Expr
    | Expr GE Expr
    | Expr NE Expr
    | Expr EQ Expr
    | Expr GT Expr
    | Expr LT Expr
    | Assignment
    | ArrayUsage
    ;
%%
#include"lex.yy.c"
#include<ctype.h>
int count=0;

int main(int argc, char *argv[])
{
    yyin = fopen(argv[1], "r");

   if(!yyparse())
        printf("\nParsing complete\n");
    else
        printf("\nParsing failed\n");

    fclose(yyin);
    return 0;
}

yyerror(char *s) {
    printf("%d : %s %s\n", yylineno, s, yytext );
}

将其组合在一起的 Makefile。我使用,但该示例也适用于

miniC:  c.l c.y
    bison c.y
    flex c.l
    gcc c.tab.c -ll -ly

编译解析测试代码:

$ make
bison c.y
flex c.l
gcc c.tab.c -ll -ly
c.tab.c: In function ‘yyparse’:
c.tab.c:1273:16: warning: implicit declaration of function ‘yylex’ [-Wimplicit-function-declaration]
       yychar = yylex ();
                ^
c.tab.c:1402:7: warning: implicit declaration of function ‘yyerror’ [-Wimplicit-function-declaration]
       yyerror (YY_("syntax error"));
       ^
c.y: At top level:
c.y:155:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 yyerror(char *s) {
 ^
$ ls
a.out  c.l  CMakeLists.txt  c.tab.c  c.y  lex.yy.c  Makefile  README.md  test
$ ./a.out test

Parsing complete

对于阅读资源,我可以推荐书籍 Modern Compiler Implementation in C by Andrew Appel 和 John Levine 的 flex/bison 书籍。

【讨论】:

  • 成功了。我一直在寻找更多的区别策略,但我可以从这里开始工作。谢谢。
  • 它不适用于 yacc/lex /usr/bin/ld: cannot find -ll
猜你喜欢
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 2013-09-17
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多