c - 编译并发 YACC 程序时出错

标签 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]
由于解析器不可重入,它使用全局 yylval类型为 YYSTYPE .您的 %union声明将创建 YYSTYPE 的声明作为 union 类型,将放置在生成的头文件中 y.tab.h ,实际上看起来像这样(省略了一些不重要的细节):

#ifndef YYSTYPE
  typedef union yystype {
    int i;
  } YYSTYPE;
  extern YYSTYPE yylval;
#endif
该代码也将被放入 y.tab.c ,但它会从 %{...} 中插入的 C 段之后进行。野牛定义的部分。给你#define YYSTYPE int , 结果在 y.tab.c yylval有类型 int ,而在 `yy.lex.c 中,它是 union 类型。那是未定义的行为 (UB),这就是您在 C 中所说的“错错错”。(但 UB 实际上是未定义的;一种可能性是错误被默默地忽略。)
由于yylvalYYSTYPE 的一个实例,而不是指向 YYSTYPE 的指针, 引用成员(member)的正确方式iyylval.i ,而不是 yylval->i .因此编译器错误。
在您的野牛文件中,您没有将任何非终结符声明为具有类型。由于您包含 %union声明中,bison 要求您告诉它使用语义值(使用 $1$2 等)或分配给(使用 $$ )的任何终端或非终端的类型。因此,当您尝试通过 bison 传递文件时,您应该收到一堆错误。 .另一方面,如果您声明了类型,那么野牛生成的解析器将包含对 yylval.i 的引用。 ,这也会产生编译器错误,因为您的 #define YYSTYPE有效地绕过了 union 声明。 (Bison 不知道 #define,因为它不解析包含的 C 代码。因此它无法生成错误消息。但这绝对是一个错误。)
如果您告诉 bison 生成一个可重入解析器,那么生成的解析器将调用 yylex带有 YYSTYPE* 类型的附加参数;你是否也提供了%option bison-bridge在 flex 定义中,flex 将生成 yylex 的声明带有 YYSTYPE* 类型的附加参数这将成为 yylval 的值.在这种情况下,yylval将是一个指针,而不是一个实例,并且 yylval->i本来是正确的。

笔记
  • 出于某种原因,使用可重入野牛解析器被错误地称为“并发 YACC”。这在两个方面是错误的:首先,生成的解析器不是并发的(尽管因为它是可重入的,如果 Action 不引入竞争条件,它可以并发使用),其次是因为该功能在 YACC 中不可用;这是一个 bison延期。
    一个快速的谷歌搜索显示了短语“Concurrent YACC”的两种用法。其中一个在 entry in ESR's blog 的评论中。 ,描述了他几十年前写的一个工具,在 bison 之前存在,使yacc解析器可重入。另一个是 Pune 大学提供的并发编程类(class)的三年级编程作业,它使用了“Concurrent YACC”这个短语,好像它很有意义。
    我猜这个问题来自第二个问题,这可能意味着类(class)作业包括对含义的解释。但是对于它的值(value),ESR 确实概述了将可重入野牛解析器正确桥接到可重入弹性词法分析器所涉及的步骤。所以我建议你看一下,虽然我不赞同ESR对%bison-bridge的描述作为 buggy 。 (如果他说“记录不充分的杂乱无章”,我会 100% 支持。)
  • 关于c - 编译并发 YACC 程序时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28508655/

    相关文章:

    c++ - 从 C/C++ 调用 Python 函数

    c - 主机顺序字节中的 ether_addr_octet

    c++ - 如何让一个类作为 printf_s/sprintf_s 的字符串?

    multithreading - 启用事务支持后,spring-data-redis 连接是否未正确释放?

    java - 有没有一种方法可以执行计时器而无需在java中创建单独的线程?

    yacc - Lex和Yacc来制作编译器?

    c - 右移按位运算中出现意外输出

    java - 多线程快速排序比预期慢很多

    linux - `...' 的 $1 在 Bison/Yacc 中没有声明类型

    c++ - 编译错误。如何使用 lex/yacc 解析变量名?