【问题标题】:Error while compiling Concurrent YACC program编译并发 YACC 程序时出错
【发布时间】:2015-02-14 08:40:25
【问题描述】:

我正在尝试使用 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);

谁能指出我做错了什么??

【问题讨论】:

  • 你好,我是浦那大学的学生,我猜你也来自同一所大学。我只是想知道,您的问题是否解决了?
  • 是的,我终于让它运行起来了。我不得不对其进行一些小的改动。在这里查看 - github.com/apoorvasomani/Lex-Yacc-Parser

标签: c multithreading yacc lex


【解决方案1】:

这是一个简单的编译器错误,这是(间接)您没有请求可重入(“纯”)野牛解析器的结果。 [注1]

由于解析器不是可重入的,它使用一个全局的yylval,它的类型是YYSTYPE。您的 %union 声明将创建一个 YYSTYPE 声明作为联合类型,该声明将放置在生成的头文件 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 中,它是联合类型。那是未定义的行为(UB),这就是您在 C 中所说的“错错错”。(但 UB 确实是未定义的;一种可能性是错误被默默地忽略了。)

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

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

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


注意事项

  1. 由于某种原因,使用可重入野牛解析器被错误地称为“并发 YACC”。这在两个方面是错误的:首先,生成的解析器不是并发的(尽管因为它是可重入的,如果动作不引入竞争条件,它可以并发使用),其次是因为该功能在 YACC 中不可用;这是bison 扩展名。

    通过 Google 快速搜索发现“Concurrent YACC”一词的两种用法。其中一个在entry in ESR's blog 的评论中,描述了他几十年前写的一个工具,在bison 存在之前,使yacc 解析器可重入。另一个是 Pune 大学提供的并发编程课程的三年级编程作业,它使用了“Concurrent YACC”这个短语,好像它很有意义。

    我猜这个问题来自其中的第二个问题,这可能意味着课程作业包含对含义的解释。但是对于它的价值,ESR 确实概述了将可重入野牛解析器正确桥接到可重入弹性词法分析器所涉及的步骤。所以我建议你看看它,虽然我不赞同 ESR 对%bison-bridge 的描述是错误的。 (如果他说“记录不充分的杂种”,我会 100% 支持。)

【讨论】:

  • 我将野牛桥添加为可重入,错误消失了,但程序以分段错误结束。有什么好的调试器吗?
  • 调试线程代码并不容易。但是,gdb 是可能的。段错误很可能不是竞争条件。在启动到多线程版本之前,我肯定会尝试验证它是否可以单线程工作。祝你好运。
猜你喜欢
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多