我正在尝试使用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);
任何人都可以指出我做错了吗?
答案 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确实是未定义的;一种可能性是错误被默默忽略。)
由于yylval
是YYSTYPE
的实例,而不是指向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
将是正确的。
出于某种原因,使用可重入的野牛解析器被错误地称为&#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%在旁边。)