结合flex和bison进行文件解析。

huangapple go评论64阅读模式
英文:

Combine flex and bison for file parsing

问题

I have this program in flex/bison.

My two problems are this:

  1. 我不知道如何使其适用于文件输入,因为我的大学作业需要它能够处理文件。

    我尝试使用g++编译器的iostream库,但遇到了许多错误(当然,我将printf改为了cout等)。

  2. 我无法将其作为浮点数运行,我使用了atof并将yytext声明为布尔型,但仍然没有得到结果。

flex.l:

%option noyywrap
%option yylineno

%{
	#include <stdlib.h>
	#include "bison.tab.h"
	#define YYDEBUG 1
%}

%%
create_table {return CREATE;}
[ ][a-z]+ {return MONO;}
([ ][a-z]+[ ]&)+ {return CREATELIST;}

create_record_data {return RECORD;}
([ ][a-z]+)([ ]#[0-9]{1,2}) {return RECORDNUMBER;}

[0-9]+(\.[0-9]+)? {yylval = atoi(yytext); return NUMBER;}
"+" {return PLUS;}
"-" {return MINUS;}
"*" {return MULT;}
"/" {return DIV;}
"\n" {printf("Line : %d \n",yylineno);  return END;}
"\t" {return TAB;}
"(" {return PARL;}
")" {return PARR;}

%%

bison.y:

%{
	#include <stdlib.h>
	#include <stdio.h>
%}

%token CREATE RECORD 
%token MONO CREATELIST RECORDNUMBER
%token NUMBER
%token PLUS MINUS MULT DIV PARL PARR
%token END TAB

%left PARL PARR
%left MULT DIV
%left PLUS MINUS

%start Input
%%

Input:
 | Input Line
;

Line:
 END
 | Expr END { printf("Result: %d \n", $1); }
 | Create_table END { printf("Create Table ! \n"); }
 | Create_record_data END { printf("Record Data Created ! \n"); }
;

Expr:
 NUMBER {$$ = $1;}
 | Expr PLUS Expr {$$=$1+$3;}
 | Expr MINUS Expr {$$=$1-$3;}
 | Expr MULT Expr {$$=$1*$3;}
 | Expr DIV Expr {$$=$1/$3;} 
 | PARL Expr PARR {$$=$2;}
 ; 

Create_table:
 CREATE MONO { printf("Create Table Single! \n"); } 
 | CREATE CREATELIST { printf("Create Table List ! \n"); }
 ;

Create_record_data:
 RECORD RECORDNUMBER Expr { printf("Record Created \n"); }
 ;

%%

int yyerror(char *s) {
  printf("%s \n", s);
}

int main() {
  if (yyparse()==0)
     fprintf(stderr, "Successful parsing.\n");
  else
     fprintf(stderr, "error found.\n");
}
英文:

I have this program in flex/bison.

My two problems are this :

  1. I don't know how to make it work for file inputs because my university exercise need it work with files.

    I tried using iostream library from g++ compiler but i had many errors (I change of course printfs in cout etc)

  2. I can't make it work as a float, I used atof declared yytext as boolean also still got nothing.

flex.l :

%option noyywrap
%option yylineno

%{
	#include &lt;stdlib.h&gt;
	#include &quot;bison.tab.h&quot;
	#define YYDEBUG 1
%}

%%
create_table {return CREATE;}
[ ][a-z]+ {return MONO;}
([ ][a-z]+[ ][&amp;])+ {return CREATELIST;}

create_record_data {return RECORD;}
([ ][a-z]+)([ ]#[0-9]{1,2}) {return RECORDNUMBER;}

[0-9]+([&quot;.&quot;][0-9]+)? {yylval = atoi(yytext); return NUMBER;}
&quot;+&quot; {return PLUS;}
&quot;-&quot; {return MINUS;}
&quot;*&quot; {return MULT;}
&quot;/&quot; {return DIV;}
&quot;\n&quot; {printf(&quot;Line : %d \n&quot;,yylineno);  return END;}
&quot;\t&quot; {return TAB;}
&quot;(&quot; {return PARL;}
&quot;)&quot; {return PARR;}

%%

bison.y :

%{
	#include &lt;stdlib.h&gt;
	#include &lt;stdio.h&gt;
%}

%token CREATE RECORD 
%token MONO CREATELIST RECORDNUMBER
%token NUMBER
%token PLUS MINUS MULT DIV PARL PARR
%token END TAB

%left PARL PARR
%left MULT DIV
%left PLUS MINUS

%start Input
%%

Input:
 | Input Line
;

Line:
 END
 | Expr END { printf(&quot;Result: %d \n&quot;, $1); }
 | Create_table END { printf(&quot;Create Table ! \n&quot;); }
 | Create_record_data END { printf(&quot;Record Data Created ! \n&quot;); }
;

Expr:
 NUMBER {$$ = $1;}
 | Expr PLUS Expr {$$=$1+$3;}
 | Expr MINUS Expr {$$=$1-$3;}
 | Expr MULT Expr {$$=$1*$3;}
 | Expr DIV Expr {$$=$1/$3;} 
 | PARL Expr PARR {$$=$2;}
 ; 

Create_table:
 CREATE MONO { printf(&quot;Create Table Single! \n&quot;); } 
 | CREATE CREATELIST { printf(&quot;Create Table List ! \n&quot;); }
 ;

Create_record_data:
 RECORD RECORDNUMBER Expr { printf(&quot;Record Created \n&quot;); }
 ;

%%

int yyerror(char *s) {
  printf(&quot;%s \n&quot;, s);
}

int main() {
  if (yyparse()==0)
     fprintf(stderr, &quot;Successful parsing.\n&quot;);
  else
     fprintf(stderr, &quot;error found.\n&quot;);
}

答案1

得分: 2

你可以在主函数中打开文件或使用标准输入(这样测试会更容易)。

如果你想要可选地接受一个输入文件名作为第一个参数,可以将主函数修改如下:

extern FILE* yyin;
int main(int argc,char **argv) {
  yyin = NULL;
  if (argc==2) yyin = fopen(argv[1],"r");
  if (!yyin) yyin = stdin;
  if (!yyparse()) {
    ...

至于你提到的关于"using"这些标记的问题。

你可以使用yytext来获取扫描器找到的触发标记的文本,但你不能直接将其分配给一个标记。你必须使用类型。

如果你想从扫描器中获取值(并且不担心语法中的yytext),那么在%token部分之前,添加以下内容:

%union
{
  int intval;
  float floatval;
}
...
%token <intval> NUMBER

然后,在你的flex.l文件中,根据标记的类型分配给联合:

[0-9]+(\.[0-9]+)? {yylval.intval = atoi(yytext); return NUMBER;}

然后,在你的语法中,你可以使用$1或$3等位置变量来访问(在这种情况下是int值)并获取该atoi值。

最后一件事,你声明了Expr的语法,但它没有类型。

在顶部部分,在你的标记之下,你必须为非终结符指定一个类型:

%type <intval> Expr // 如果Expr只是一个数字

如果你想在非终结符中存储更多信息,那么你可能应该创建/使用一个结构体,在联合中声明其类型,然后你可以将NT的类型设置为你的结构体。

唯一分配$$(产生式规则的左侧)的方法是给$$指定一个类型。使用上述方式,将Expr分配为int类型,将数字分配为int类型应该可以工作:

Expr : Expr PLUS Expr { $$ = $1 + $3; }
英文:

In your main you can open a file or use stdin (this makes testing easier).

Say if you want to optionally accept an input filename as your first argument, change your main to look like:

extern FILE* yyin;
int main(int argc,char **argv) {
  yyin = NULL;
  if (argc==2) yyin = fopen(argv[1],&quot;r&quot;);
  if (!yyin) yyin = stdin;
  if (!yyparse()) {
    ...

For your other issue of "using" the tokens.

You can use the yytext to get the text that the scanner found that triggered the token, but you can't assign just assign this to a token. You have to use types.

If you want to get the value from the scanner (and not worry about yytext in the grammar, then above your %token section, add this:

%union
{
  int intval;
  float floatval;
}
...
%token &lt;intval&gt; NUMBER

Then, in your flex.l, you can assign to the union according to whatever type the token is:

[0-9]+([&quot;.&quot;][0-9]+)? {yylval.intval = atoi(yytext); return NUMBER;}

Then, in your grammar, you can access the (int value in this case) using the $1 or $3 / etc. positional variable and get that atoi value.

Last thing, is you declare grammar for Expr but it has no type.

In the top section, below your tokens, you have to give non-terminals a type:

%type &lt;intval&gt; Expr // if an Expr is just a number

If you want to store more information in a Non-Terminal then you should probably make/use a struct, declare its type in the union, then you can set the type of the NT to your struct.

The only way to assign $$ (the left side of the production rule) is for $$ to have a type. With the above, giving Expr an int and the numbers ints ...

Expr : Expr PLUS Expr { $$ = $1 + $3; }

should work

huangapple
  • 本文由 发表于 2023年5月14日 01:05:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76243978.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定