我正在尝试使用 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 实际上是未定义的;一种可能性是错误被默默地忽略。)由于
yylval
是 YYSTYPE
的一个实例,而不是指向 YYSTYPE
的指针, 引用成员(member)的正确方式i
是 yylval.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
本来是正确的。笔记
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/