3

私は lex と yacc を試していて、奇妙な問題に遭遇しましたが、問題を詳しく説明する前に私のコードをお見せするのが最善だと思います。これは私のレクサーです:

%{
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"
void yyerror(char *);
%}

%%

[a-zA-Z]+ {
  yylval.strV = yytext;
  return ID;
}

[0-9]+      {
  yylval.intV = atoi(yytext);
  return INTEGER;
}

[\n] { return *yytext; }

[ \t]        ;

. yyerror("invalid character");

%%

int yywrap(void) {
  return 1;
}

これは私のパーサーです:

%{
#include <stdio.h>

int yydebug=1;
void prompt();
void yyerror(char *);
int yylex(void);
%}

%union {
  int intV;
  char *strV;
}

%token INTEGER ID

%%

program: program statement EOF { prompt(); }
       | program EOF { prompt(); }
       | { prompt(); }
       ;

args: /* empty */
    | args ID { printf(":%s ", $<strV>2); }
    ;

statement: ID args { printf("%s", $<strV>1); }
         | INTEGER { printf("%d", $<intV>1); }
;

EOF: '\n'

%%

void yyerror(char *s) {
  fprintf(stderr, "%s\n", s);
}

void prompt() {
  printf("> ");
}

int main(void) {
  yyparse();
  return 0;
}

文字列と整数、および基本的な REPL だけで構成される、非常に単純な言語。ここで、パーサーで、引数が先頭のコロンで出力されることに注意してください。意図は、ステートメントの規則の最初のパターンと組み合わせると、REPL との相互作用が次のようになります。

> aaa aa a
:aa :a aaa>

ただし、相互作用は次のとおりです。

> aaa aa a
:aa :a aaa aa aa
>

次のルールでトークン ID が

statement: ID args { printf("%s", $<strV>1); }
         | INTEGER { printf("%d", $<intV>1); }
;

改行を含めて、入力文字列全体の意味値を持っていますか? 意図した対話ができるように、どのように文法を作り直すことができますか?

4

2 に答える 2

2

トークン文字列を有効なままにしておきたい場合は、読み取られるときにトークン文字列を保持する必要があります。statementルールを次のように変更しました。

statement: ID { printf("<%s> ", $<strV>1); } args { printf("%s", $<strV>1); }
         | INTEGER { printf("%d", $<intV>1); }
;

次に、あなたの入力で、私は出力を取得します:

> aaa aa a
<aaa> :aa :a aaa aa a
>

初期IDが読み取られる時点で、トークンは正確に期待どおりであることに注意してください。ただし、トークンを保存しなかったため、args解析後に文字列の印刷に戻るまでに文字列が変更されています。

于 2010-04-26T13:52:40.880 に答える
0

引数とステートメント生成の間に結合性の競合があると思います。bison -vこれは、 parser.output ファイルからの (部分的な) 出力によって裏付けられています。

Nonterminals, with rules where they appear

$accept (6)
    on left: 0
program (7)
    on left: 1 2 3, on right: 0 1 2
statement (8)
    on left: 4 5, on right: 1
args (9)
    on left: 6 7, on right: 4 7
EOF (10)
    on left: 8, on right: 1 2

確かに、あなたの文法が何を受け入れようとしているのかを理解するのに苦労しています。補足として、私はおそらくあなたの EOF プロダクションを EOL トークンとしてレクサーに移動したいと思います。これにより、解析エラーでの再同期が容易になります。

あなたの意図のより良い説明は役に立ちます。

于 2010-04-23T06:18:54.893 に答える