1

パーサーを実装しましたが、何も出力されません。指定された入力が構文的に間違っている場合、yyerror()ルーチンに含めても「エラー」は出力されません。また、入力が正しければ、解析ツリーは出力されません。これの考えられる理由は何でしょうか?ファイルではなくファイルに入れmain()ました。それが考えられる理由ですか?これが主な方法です。.lex.y

int main( argc, argv )
int argc;
char **argv;
{
    ++argv, --argc; 
    if ( argc > 0 )
    yyin = fopen( argv[0], "r" );
    else
    yyin = stdin;     

    yyparse();
}

文法ファイルは次のとおりです。

%{
#include "parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
%}

%union {
  char* a_variable;
  tree* a_tree;
}

%start file
%token <a_variable> TOKID TOKSEMICOLON TOLCOLON TOKCOMMA TOKUNRECOG TOKDOT TOKMINUS TOKCOLON
%type <a_tree> field file obj ID
%right TOKMINUS

%%

file      :     /*empty*/ { return NULL; }
      |     field file { printtree($1, 1);  }
  ;

field     : ID TOKCOLON field {$$ = make_op($1, ':', $3); }
  | ID TOKCOMMA field {$$ = make_op($1, ',', $3); }
  | obj { $$ = $1; }
  ;

obj       :     ID TOKSEMICOLON { $$ = make_op($1, ';', NULL); }
      ;

ID        :     TOKID { $$ = $1; }

%%

#include <stdio.h>
yyerror(char *str)
{
  fprintf(stderr,"error FAIL: %s\n",str);
}

int yywrap()
{
  return 1;
}

これが私の.lexファイルの外観です。

%{
/* need this for the call to atof() below */
#include <math.h>
#include "parser.h"
#include "idf.tab.h"
%}

DIGIT    [0-9]
ID       [a-zA-Z]*
%option noyywrap

%% 


{ID} |  
-?{DIGIT}+"."{DIGIT}* |    
-?{DIGIT}+      { yylval.a_variable = findname(yytext); return TOKID; }

";"           return TOKSEMICOLON;
":"           return TOKCOLON;
","           return TOKCOMMA;
"."           return TOKDOT;
"-"           return TOKMINUS; 
.           return TOKUNRECOG;
%%

int main( int argc, char** argv )
{
++argv, --argc; 
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;

yyparse();
}
4

2 に答える 2

1

複数のルールを次のように1つに組み合わせることができるかどうかはわかりません。

{ID} |  -?{DIGIT}+"."{DIGIT}* |    -?{DIGIT}+      return TOKID;

lexは空白に敏感です。私はそれがこのようになるべきだと思います:

{ID} |
-?{DIGIT}+"."{DIGIT}* |
-?{DIGIT}+      return TOKID;

この|文字は、「次の行と同じアクション」を意味する特殊なアクションとして解釈されます。パターン内|は正規表現ブランチを示します。しかし、そこにはこれらすべてのスペースがあります。

コメントマッチャーは偽物に見えます:

"{"[\^{}}\n]*"}"     /* eat up one-line comments */   

ここで否定された文字クラスが必要だったと思いますが、^文字にエスケープを設定すると、単に^文字クラスに含まれるようになります。

これのポイントは何ですか:

"!"+"-"[\n] return TOKCOMMENT;

シーケンスの!後に-と改行が続くのは、無視していないが、トークンとして返されるある種のコメントです。

レクサーの動作が壊れているため、この解析ルールは正しく機能しません。

ID        :     TOKID { $$ = $1; }

セマンティックタイプを持つものとして定義したため、式$1はアクセスしたいと考えています。しかし、生成するlexルールは何も入れません。それはただそうし、そのポインタをゴミを含むように残します。レクサールールはに割り当てる必要があります。yystack[<whatever>].a_variableTOKIDa_variableTOKIDa_variablereturn TOKID;yylval.a_variable

LexとYaccは、あなたが思っているよりもはるかに自動化されていません。

于 2012-04-03T22:28:52.127 に答える
1

関数yylex()は字句スキャナーであり、文法パーサーではありません。パーサーはyyparse(). yyparse()したがって、プログラムをの代わりにcall するように更新し、新しいトークンが必要なときに callyylex()を残します。yyparse()yylex()

while (yyparse() != 0)
    ;

空のループ本体の代わりに解析ツリーの出力を行うか、文法自体の開始規則から呼び出される関数で出力を行う場合があります。

余談ですが、 の K&R 宣言を使用する正当な理由が思いつきませんmain()。常に使用しますint main(int argc, char **argv)。また、K&R 表記法を使用する場合はmain()、慣習的に成功した場合はゼロ、失敗した場合はゼロ以外の値を返す必要があります。C99 では、 (の唯一の非常に例外的な場合main()と同等の) からの最終的な戻り値を省略できますが、それを含めることをお勧めします。return 0;main()


その後の注意事項

あなたが助けを求めていることを人々が簡単にテストできるようにすることは良い考えです。コンパイル可能にするのに十分なソースを提供します。コンパイル作業を最小限に抑えるために、十分なソースを削除してください。

文法のさまざまなアクション機能を中和することはそれほど難しくありませんでした。のparser.hようなものを含む必要があるファイルtypedef struct tree tree;。そして、文法は である必要があったidf.yため、 とbison -d idf.yが生成さidf.tab.hidf.tab.cます。

私が字句解析器で最初に行うことの 1 つは、実行内容を出力することです。そこで、次のようなことを行うようにルールを変更しました。

{ID} |  
-?{DIGIT}+"."{DIGIT}* |    
-?{DIGIT}+      { printf("ID or number: %s\n", yytext); /*yylval.a_variable = findname(yytext);*/ return TOKID; }

";"           { printf("Semi-colon\n"); return TOKSEMICOLON;}
":"           { printf("Colon\n"); return TOKCOLON;}

これは、スペースや改行を非常に適切に処理していないことをすぐに示しました。そのためには、おそらく規則が必要です (そして、それらの規則はおそらく文法に戻りません)。

[ \t]         { printf("White space\n"); }

もちろん、それは「ゴブリング ドット」ルールの前に表示される必要があります。

これで、プログラムを実行して字句出力を得ることができました。

$ ./idf
abc ;
ID or number: abc
White space
Semi-colon

$

私はそれを入力abc ;し、それらはOKであると識別しました。文法にはアクションにコードが残っていないため、文法自体からの出力はありませんでした。-DYYDEBUG関数を使用してコンパイルし、設定yydebug = 1;することはおそらく価値があります — そこに字句解析器のソース ファイルmain()を追加する必要があるかもしれません。extern int yydebug;main()

$ flex scanner.l
$ bison -d idf.y
$ gcc -DYYDEBUG -o idf idf.tab.c lex.yy.c
$ ./idf
Starting parse
Entering state 0
Reading a token: abc ;
ID or number: abc
Next token is token TOKID ()
Shifting token TOKID ()
Entering state 1
Reducing stack by rule 7 (line 32):
   $1 = token TOKID ()
-> $$ = nterm ID ()
Stack now 0
Entering state 5
Reading a token: White space
Semi-colon
Next token is token TOKSEMICOLON ()
Shifting token TOKSEMICOLON ()
Entering state 8
Reducing stack by rule 6 (line 29):
   $1 = nterm ID ()
   $2 = token TOKSEMICOLON ()
-> $$ = nterm obj ()
Stack now 0
Entering state 4
Reducing stack by rule 5 (line 26):
   $1 = nterm obj ()
-> $$ = nterm field ()
Stack now 0
Entering state 3
Reading a token: 
Now at end of input.
Reducing stack by rule 1 (line 20):
$

今、あなたの問題はあなたが示していない機能にあります。それらはあなたが解決するものです。

于 2012-04-03T15:59:09.757 に答える