トークンの実際の文字列を渡したい。IDというトークンがある場合は、yaccファイルに実際にIDと呼ばれるものを認識させたいと思います。私はyylvalを使用して文字列をflexファイルからyaccファイルに渡さなければならないことです。それ、どうやったら出来るの?
3 に答える
yylval を介して文字列または任意の複合型を返すための鍵は、yacc によって y.tab.h ファイルに作成された YYSTYPE 共用体です。YYSTYPE は、yacc ソース ファイル内で定義された各タイプのトークンのメンバーを持つ共用体です。たとえば、yacc ソース ファイルで SYMBOL トークンに関連付けられた文字列を返すには、yacc ソース ファイルで%unionを使用してこの YYSTYPE 共用体を宣言します。
/*** Yacc's YYSTYPE Union ***/
/* The yacc parser maintains a stack (array) of token values while
it is parsing. This union defines all the possible values tokens
may have. Yacc creates a typedef of YYSTYPE for this union. All
token types (see %type declarations below) are taken from
the field names of this union. The global variable yylval which lex
uses to return token values is declared as a YYSTYPE union.
*/
%union {
long int4; /* Constant integer value */
float fp; /* Constant floating point value */
char *str; /* Ptr to constant string (strings are malloc'd) */
exprT expr; /* Expression - constant or address */
operatorT *operatorP; /* Pointer to run-time expression operator */
};
%type <str> SYMBOL
次に、LEX ソース ファイルには、SYMBOL トークンに一致するパターンがあります。SYMBOL を表す実際の文字列を返すのは、その規則に関連付けられたコードの役割です。一致するトークンごとに再利用される静的バッファーであるため、yytext バッファーにポインターを渡すことはできません。一致したテキストを返すには、_strdup() と yyval.str を介して渡されるこの文字列へのポインターを使用して、静的な yytext バッファーをヒープに複製する必要があります。SYMBOL トークンの責任に一致するのは yacc ルールであり、ヒープに割り当てられた文字列が使用されたときに解放されます。
[A-Za-z_][A-Za-z0-9_]* {{
int i;
/*
* condition letter followed by zero or more letters
* digits or underscores
* Convert matched text to uppercase
* Search keyword table
* if found
* return <keyword>
* endif
*
* set lexical value string to matched text
* return <SYMBOL>
*/
/*** KEYWORDS and SYMBOLS ***/
/* Here we match a keywords or SYMBOL as a letter
* followed by zero or more letters, digits or
* underscores.
*/
/* Convert the matched input text to uppercase */
_strupr(yytext); /* Convert to uppercase */
/* First we search the keyword table */
for (i = 0; i<NITEMS(keytable); i++) {
if (strcmp(keytable[i].name, yytext)==0)
return (keytable[i].token);
}
/* Return a SYMBOL since we did not match a keyword */
yylval.str=_strdup(yytext);
return (SYMBOL);
}}
YACC とのインターフェイスに関する Flex マニュアルのセクションを参照してください。
15 yacc とのインターフェース
flex の主な用途の 1 つは、yacc パーサージェネレーターのコンパニオンとして使用することです。yacc パーサーは、次の入力トークンを見つけるために yylex() という名前のルーチンを呼び出すことを想定しています。このルーチンは、次のトークンのタイプを返すだけでなく、関連する値をグローバル yylval に入れることになっています。yacc で flex を使用するには、yacc に「-d」オプションを指定して、yacc 入力に現れるすべての %tokens の定義を含むファイル y.tab.h を生成するように指示します。このファイルは、flex スキャナーに組み込まれます。たとえば、トークンの 1 つが TOK_NUMBER の場合、スキャナーの一部は次のようになります。
%{ #include "y.tab.h" %} %% [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
コンテキストの設定
構文解析 (入力テキストが指定された文法に従っているかどうかを確認するため) は、次の 2 つのフェーズで構成されます。
- lex や flex などのツールによって、インターフェイス yylex()) と
- ステップ 1 で生成されたトークンのストリームを (ユーザー指定の文法に従って) 解析します。これは、インターフェース yyparse() を使用した bison/yacc などのツールによって行われます。
フェーズ 1を実行している間、入力ストリームが与えられると、yylex() への各呼び出しはトークン (char 文字列) を識別し、yytext はその文字列の最初の文字を指します。C 言語に準拠したトークン化の lex 規則を使用すると、yylex() への最初の 5 回の呼び出しで、次の 5 つのトークン「int」、「x」、「=」、「10」、「;」が識別されます。yytext が戻りトークンの最初の文字を指すたびに。
フェーズ 2、パーサー ( yacc として言及) は、毎回この yylex 関数を呼び出してトークンを取得し、これらのトークンを使用して文法の規則に一致しているかどうかを確認するプログラムです。yylex へのこれらの呼び出しは、いくつかの整数コードとしてトークンを返します。たとえば、前の例では、yylex() への最初の 5 回の呼び出しで、次の整数がパーサーに返される可能性があります: TYPE、ID、EQ_OPERATOR、および INTEGER (これらの実際の整数値は、ヘッダー ファイルで定義されています)。
現在、パーサーが認識できるのはこれらの整数コードだけですが、これは時々役に立たないかもしれません。たとえば、実行中の例では、TYPE を int に、ID をシンボル テーブル ポインターに、INTEGER を 10 進数の 10 に関連付けることができます。これを容易にするために、yylex によって返される各トークンは、デフォルトの型が int である別の VALUE に関連付けられていますが、そのためのカスタムタイプがあるかもしれません。lex 環境では、この VALUE は yylval としてアクセスされます。
たとえば、実行中の例のように、yylex は 10 を識別するために次のルールを持つ場合があります。
[0-9]+ { yylval.intval = atoi(yytext); return INTEGER; }
および x を特定するための次の手順
[a-zA-Z][a-zA-Z0-9]* {yylval.sym_tab_ptr = SYM_TABLE(yytext); return ID;}
ここで、VALUE (または yylval) の型を int (intval) と int* ポインター (sym_tab_ptr) を含む共用体として定義したことに注意してください。
しかし、yacc の世界では、この VALUE は $n として識別/アクセスされます。たとえば、特定の割り当てステートメントを識別する次の yacc ルールを考えてみましょう。
TYPE ID '=' VAL: { //In this action part of the yacc rule, use $2 to get the symbol table pointer associated with ID, use $4 to get decimal 10.}
あなたの質問に答える
yacc ワールドで特定のトークン (lex ワールドに関連する) の yytext 値にアクセスする場合は、次のように旧友の VALUE を使用します。
- VALUE の共用体タイプを拡張して、char* lex_token_str などの別のフィールドを追加します
- lex ルールでは、yylval.lex_token_str = strdup(yytext) を実行します。
- 次に、yacc ワールドで、適切な $n を使用してアクセスします。
- トークンの複数の値にアクセスする場合 (たとえば、lex で識別されたトークン ID の場合、パーサーは名前とシンボル テーブル ポインターの両方にアクセスする必要がある場合があります)、VALUE の共用体型をchar* (名前用) および int* (symtab ポインター用) を含む構造体メンバー。