编译并发YACC程序时出错

时间:2015-02-13 21:00:46

标签: c multithreading yacc lex

我正在尝试使用Concurrent YACC构建一个基本计算器。我通过静态创建线程来尝试代码。但是,当我想动态指定要创建的线程数时,解析器似乎有问题。这是我的代码的内容。

aa.y档案

%{
#include <stdio.h>
#include <pthread.h>
#include <string.h>
void * scanner;
FILE *yyin;
#define YYSTYPE int
%}

%token digit
%lex-param {void * scanner}
%parse-param {void * scanner}
%start list
%token NUMBER
%left '+' '-'
%left '*' '/' '%'
%left UMINUS 
%union {int i;}
%%

list:                      
    |
    list stat '\n'
    |
    list error '\n'{ yyerrok; }
    ;

stat:   expr { printf("Thread = %d ... Ans = %d\n",pthread_self(),$1);}
    ;

expr:   '(' expr ')'{ $$ = $2; }
    |
    expr '*' expr { $$ = $1 * $3; }
    |
    expr '/' expr { $$ = $1 / $3; }
    |
    expr '+' expr { $$ = $1 + $3; }
    |
    expr '-' expr { $$ = $1 - $3; }
    |
    '-' expr %prec UMINUS { $$ = -$2; }
    |
    NUMBER
    ;

%%

struct struct_arg
{
    unsigned char* file;
};

int yyerror()
{
    return 1;
}

void *parse(void *arguments)
{
    struct struct_arg *args = (struct struct_arg *)arguments;
    unsigned char* filename;
    filename = args -> file;
    yyin = fopen(filename,"r+");
    if(yyin == NULL)
   {

   }
   else
   {
       yylex_init(&scanner);
       yyset_in(yyin,scanner);
       yyparse(scanner);
       yylex_destroy(scanner);
       printf("Thread = %d\n",pthread_self());
   }

   fclose(yyin);
}

int main(int argc, char *argv[])
{
    int num;
    printf("How many threads you want to create??\n");
    scanf("%d", &num);

    int error, count = 0;
    FILE *fp[num], *file_pointer;
    char line[256];
    size_t len = 0;
    char read;

    file_pointer = fopen("test.txt", "r");

    while (fgets(line, sizeof(line), file_pointer))
    {
        char file_name[32] = "test_";
        char dummy[4];
        char dummy2[5] = ".txt";
        sprintf(dummy, "%d", count);
        strcat(file_name, dummy);
        strcat(file_name, dummy2);
        fp[count] = fopen(file_name, "a");
        fprintf(fp[count], "%s", line);
        fclose(fp[count]);
        count++;
        if(count == num)
        {
            count = 0;
        }
    }

    struct struct_arg arguments[num];
    int i = 0;
    while(i < num)
    {
        char file_name[32] = "test_";
        char dummy[4];
        char dummy2[5] = ".txt";
        sprintf(dummy, "%d", i);
        strcat(file_name, dummy);
        strcat(file_name, dummy2); 
        arguments[i].file = file_name;
        i++;
    }

    pthread_t tid[num];
    int j = 0;
    while(j < num)
    {
        error = pthread_create(&(tid[j]), NULL, &parse, (void *) &arguments[j]);
        j++;
    }

    int n = 0;
    while(n < num)
    {
        pthread_join(tid[n], NULL);
        n++;
    }

    int temp, k = 0;
    while(k < num)
    {
        char file_name[32] = "test_";
        char dummy[4];
        char dummy2[5] = ".txt";
        sprintf(dummy, "%d", k);
        strcat(file_name, dummy);
        strcat(file_name, dummy2); 
        temp = remove(file_name);
        k++;
    }

    return 0;
}

aa.l

%{
#include <stdio.h>
#include "y.tab.h"
extern int scanner;
%}
%option reentrant
%option noyywrap
NUMBER      [0-9]+
%%

" "         ;
{NUMBER}    {
                yylval->i = atoi(yytext);
                return(NUMBER);
            }
[^0-9\b]    {
                return(yytext[0]);
            }

我的编译步骤是

yacc -d aa.y
lex aa.l
cc lex.yy.c y.tab.c -o aa.exe -pthread

产生的错误是

aa.l: In function 'yylex':
aa.l:13:23: error: invalid type argument of '->' (have 'YYSTYPE')
            yylval->i = atoi(yytext);

任何人都可以指出我做错了吗?

1 个答案:

答案 0 :(得分:1)

这是一个简单的编译器错误,它(间接地)是您未请求可重入(&#34;纯&#34;)野牛解析器的结果。 [注1]

由于解析器不可重入,因此它使用类型为yylval的全局YYSTYPE。您的%union声明将创建YYSTYPE作为联合类型的声明,它将放置在生成的头文件y.tab.h中,实际上看起来像这样(省略一些不重要的细节):

#ifndef YYSTYPE
  typedef union yystype {
    int i;
  } YYSTYPE;
  extern YYSTYPE yylval;
#endif

该代码也将放入y.tab.c,但在之后从您的野牛定义的%{...}部分插入段后。在那里你#define YYSTYPE int,结果在y.tab.c yylval中有int类型,而在`yy.lex.c中,它是一个联合类型。那个未定义的行为(UB),就是你怎么说&#34;错误的错误&#34;在C.(但UB确实是未定义的;一种可能性是错误被默默忽略。)

由于yylvalYYSTYPE的实例,而不是指向YYSTYPE的指针,因此引用成员i的正确方法是yylval.i,不是yylval->i。因此编译错误。

在您的野牛文件中,您不会声明任何非终结者有类型。由于您要包含%union声明,因此bison要求您告诉它使用其语义值的任何终端或非终端的类型(使用$1$2等。)或分配给($$)。因此,当您尝试通过bison传递文件时,您应该收到一堆错误。另一方面,如果你已经声明了类型,那么bison生成的解析器将包含对yylval.i的引用,这也会产生编译器错误,因为你的#define YYSTYPE有效地绕过了union声明。 (Bison不知道#define因为它没有解析包含的C代码。所以它不能生成错误信息。但它绝对是一个错误。)

如果你告诉bison产生一个可重入的解析器,那么生成的解析器会调用yylex并附加一个类型为YYSTYPE*的参数;如果你还在flex定义中提供了%option bison-bridge,那么flex会生成yylex的声明,其中附加的YYSTYPE*参数将成为yylval的值。在这种情况下,yylval将是一个指针,而不是一个实例,而yylval->i将是正确的。


备注

  1. 出于某种原因,使用可重入的野牛解析器被错误地称为&#34;并发YACC&#34;。这有两个方面的错误:首先,生成的解析器不是并发的(尽管因为它是可重入的,如果动作不引入竞争条件,它可以同时使用),其次因为该特征不是可在YACC获得;它是bison扩展名。

    Google快速搜索显示了短语&#34; Concurrent YACC&#34;的两种用法。其中一个是在entry in ESR's blog的评论中,描述了他几十年前在bison存在之前编写的工具,以使yacc解析器可以重入。另一个是在浦那大学提供的并发编程课程中的第三年编程作业,该课程使用短语&#34; Concurrent YACC&#34;好像它有意义。

    我猜这个问题来源于其中的第二个问题,这可能意味着课程内容包括对其含义的解释。但是对于它的价值,ESR确实概述了将可重入的野牛解析器正确桥接到可重入的flex lexer所涉及的步骤。所以我建议你看看它,虽然我并不认可ESR对%bison-bridge的描述是错误的。 (如果他说&#34;严重记录的kludge&#34;,我会100%在旁边。)