0

与えられたプレフィックス/インフィックス/ポストフィックス電卓にビット単位の演算子を追加しようとしましたが、何らかの理由で、yacc を使用して演算子 "<<" ">>" "**" を認識させることができません。同様の問題、特にこの質問yacc/bison tokens errorを抱えている他の人を探しました。'>>>' と '>>' は両方とも番号 62を割り当てましたが、有効な解決策は見つかりませんでした。

私のlexファイル

%{
#include "zcalc.h"
#include <math.h>

int ch;
int flag = 0;

#define NAME 257            
#define SEMISYM 268 
#define COMMASYM 269 
#define LPARSYM 270
#define RPARSYM 271
#define EQSYM 272 
#define PLUSSYM 273
#define MULTSYM 274
#define ASGNSYM 275 
#define MINUSSYM 276 
#define NUMBER 277
#define TILDE 278

/*New stuff I added*/
#define BITAND 279
#define BITOR 280
#define BITXOR 281
/*#define BITNOT 282*/
#define LSHIFT 283
#define RSHIFT 284
#define POWER 285

void yyerror( char *mesg ); /* yacc error checker */



/* definitions for lex analyzer */
letter [A-Za-z]         
digit  [0-9]+       
ident {letter}({letter}|{digit})*           
ws  [ \t\n]+                
other  .


%%

{ws}  ;         /*---- Tokens and Actions---- */
/*New Stuff*/
"&" return BITAND;
"|" return BITOR;
"^" return BITXOR;
"<<" return LSHIFT;
">>" return RSHIFT;
"**" return POWER;

"//".* ;                
";" return SEMISYM;         
"," return COMMASYM;            
"(" return LPARSYM; 



")" return RPARSYM;         
"==" return EQSYM;          
"+" return PLUSSYM;         
"*" return MULTSYM;         
"=" return ASGNSYM;         
"-" return MINUSSYM;
"~" return TILDE;

/*New Stuff
"&" return BITAND;
"|" return BITOR;
"^" return BITXOR;
"<<" return LSHIFT;
">>" return RSHIFT;
"**" return POWER;*/


{ident}     {
                 return NAME;
            }

{digit}     {
                 return NUMBER;
            }

"$"   { return 0; }

{other} ;               /* ignore other stuff */

%%

void yyerror( char *mesg ); /* yacc error checker */

/* yacc error function */
void yyerror( char *mesg ) {
  flag = 1;
  printf("%s \n" , mesg);  
}

int main() {
  printf("Lex  \t\tToken\t\t\n"); /* header on columns */
  printf("----------------------------\n"); 
  do
  {
    ch = yylex();

    if (ch == SEMISYM)
      printf("%s\t\tSEMICOLON ", yytext);
    else if (ch == COMMASYM)
      printf("%s\t\tCOMMA ", yytext);
    else if (ch == LPARSYM)
      printf("%s\t\tL_PARENTHESIS ", yytext);
    else if (ch == RPARSYM)
      printf("%s\t\tR_PARENTHESIS ", yytext);
    else if (ch == EQSYM)
      printf("%s\t\tEQ_OP ", yytext);
    else if (ch == PLUSSYM)
      printf("%s\t\tPLUS_OP ", yytext);
    else if (ch == MULTSYM)
      printf("%s\t\tMULT_OP ", yytext);
    else if (ch == ASGNSYM)
      printf("%s\t\tASSIGNMENT_STMT ", yytext);
    else if (ch == MINUSSYM)
      printf("%s\t\tMINUS_OP ", yytext);
    else if (ch == NUMBER)
      printf("%s\t\tNUMBER ", yytext);
    else if (ch == NAME)
      printf("%s\t\tNAME\t\t", yytext);
     else if (ch == TILDE)
        printf("%s\t\tTILDE\t\t", yytext);
        else
         printf("%c ",ch);
         printf("\n");          /* end check token read */
       }
       while(ch != 0);          /* read until end of file */    

      return 0;
    }

    int yywrap() {
      return 1;
    }

    %}

そして私のyaccファイル

    %{ 
#include "zcalc.h"

#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>




int flag = 0;

void yyerror( char *mesg ); /* yacc error checker */

%}

%union {
  double dval;
  struct symtab *symp;
}

%token <symp> NAME
%token <dval> NUMBER
 // %token LSHIFT
 // %token RSHIFT
%token POWER

%left '-' '+'
 //%left "**"
%left '*' '/'
 //%left LSHIFT RSHIFT
 //%left POWER

%type <dval> expression
%%

statement_list: statement '\n'
                | statement_list statement '\n'

statement: NAME '=' expression { $1->value = $3; }
           | expression { printf("= %g\n", $1); }

expression: '+' expression expression { $$ = $2 + $3; }
            | '-' expression expression { $$ = $2 - $3; }
            | POWER expression expression { $$ = $3; }
            | '*' expression expression { $$ = $2 * $3; }
            | '/' expression expression { $$ = $2 / $3; }
            | '&' expression expression { $$ = (int)$2 & (int)$3; }
            | '|' expression expression { $$ = (int)$2 | (int)$3; }
            | '^' expression expression { $$ = (int)$2 ^ (int)$3; }
            | '<' '<' expression expression { $$ = (int)$3 << (int)$4; }
            | '>' '>' expression expression { $$ = (int)$3 >> (int)$4; }
//| "**" expression expression { $$ = pow($2, $3); }
            | '~' expression { $$ = ~ (int)$2; }
            | '(' expression ')' { $$ = $2; }
            | NUMBER
            | NAME { $$ = $1->value; }
%%

struct symtab * symlook( char *s ) {
   char *p;
   struct symtab *sp;

   for(sp = symtab; sp < &symtab[NSYMS]; sp++) {
     /* is it already here? */
     if (sp->name && !strcmp(sp->name, s))
       return sp;

     /* is it free */
     if (!sp->name) {
       sp->name = strdup(s);
       return sp;
     }
     /* otherwise continue to the next */
   }
   yyerror("Too many symbols...\n");
   exit(1);
}

void addfunc( char *name, double (*func)() ) {
  struct symtab *sp = symlook(name);
  sp->funcptr = func;
}


/* yacc error function */
void yyerror( char *mesg )  {
  flag = 1;
  printf("%s \n" , mesg);  
}


int main() {

  yyparse();

  return 0;
}

ヘッダー内の定義とルールの配置をいじりましたが、うまくいかないようでした。'<' '<' を使用して "<<" と ">>" を機能させることはできますが、引数のカウントがオフになり、適切な解決策というよりも回避策のように思えます。助けてくれてありがとう!

4

3 に答える 3

1

問題は、バイソンのようなトークンを定義して使用することはできますが"<<"">>"そのようなトークンには .tab.h ファイルで定義された値に展開されるマクロがないため、トークンを生成する (簡単な) 方法がないことです。レクサー。それらを使用するには、bison が割り当てたトークン値 (整数) を特定し (.output ファイルで確認できます)、その整数を返す必要があります。しかし、.y ファイルを変更すると (新しいトークンが追加されたり、順序が変更されたりしても)、それが変更される可能性があるため、維持することはほとんど不可能です。

LSHIFT代わりに、bison がトークン番号に展開されるマクロを生成する名前トークン (や など)を定義する方が理にかなっていますRSHIFT。これにより、レクサーでそれらを簡単に参照できます。

于 2013-03-04T04:27:28.180 に答える
1

使用することをお勧めします

%token LSHIFT "<<"
...
%left "<<"
...
expression: expression "<<" expression {...}

Bison ファイルと Flex ファイルでは次のようになります。

"<<"  return LSHIFT;

あなたが書いたように"<<"ではなく、文法ファイルで使用することに注意してください。'<<'

于 2013-03-04T12:43:40.183 に答える
0

Flex ソースが正しくありません。最後に%}ファイルの途中にあるはずですが、それは非常にひどいので、素材をSOにコピーする際に問題になるはずです(%}質問に示されている場所で「時期尚早のEOF」が発生します)。

テスト ハーネスは、新しいエントリを出力するようにアップグレードされませんでした。else句を次のように変更すると:

    else
        printf("%d\t\tUNKNOWN (%s)",ch, yytext);

次に、このシンボルのポプリでテスト プログラムを実行すると、次のように動作するようです。

Lex         Token       
----------------------------
()+*=-~ &|^>>**<<;,()===
(       L_PARENTHESIS
)       R_PARENTHESIS
+       PLUS_OP
*       MULT_OP
=       ASSIGNMENT_STMT
-       MINUS_OP
~       TILDE
279     UNKNOWN (&)
280     UNKNOWN (|)
281     UNKNOWN (^)
284     UNKNOWN (>>)
260     UNKNOWN (**)
283     UNKNOWN (<<)
;       SEMICOLON
,       COMMA
(       L_PARENTHESIS
)       R_PARENTHESIS
==      EQ_OP
=       ASSIGNMENT_STMT
0       UNKNOWN ()

それ以前は、明らかに空白行を出力していましたが、実際には 279-283 が 256 を法として文字コード 23-27 に、または control-W が control-[ に縮小されるため、制御文字がありました。

于 2013-03-04T06:58:28.163 に答える