スキャナは、一致した入力テキストを yytext[] に格納する以外にも、一致した入力テキストの文字数をカウントしてその値を変数 yyleng に自動的に格納します。ユーザーは、この変数を使用して、配列 yytext[] に配置された任意の文字を参照できます。
C 言語の配列インデックスは 0 から始まります。したがって、認識した整数の 3 桁目の数字 (3 桁目の数字がある場合) を出力するには、以下のように記述します。
[1-9]+ {if (yyleng > 2) printf("%c", yytext[2]); }
記述した一連の規則によってあいまいさが生じた場合、lex は上位のルールに従ってそのあまいさを解決します。以下の字句アナライザの例では、「予約語」end は 2 番目の規則と、識別子用の 8 番目の規則に一致します。
begin return(BEGIN); end return(END); while return(WHILE); if return(IF); package return(PACKAGE); reverse return(REVERSE); loop return(LOOP); [a-zA-Z][a-zA-Z0-9]* { tokval = put_in_tabl(); return(IDENTIFIER); } [0-9]+ { tokval = put_in_tabl(); return(INTEGER); } ¥+ { tokval = PLUS; return(ARITHOP); } ¥- { tokval = MINUS; return(ARITHOP); } > { tokval = GREATER; return(RELOP); } >= { tokval = GREATEREQL; return(RELOP); }
lex は、仕様内の 2 個以上の規則と一致する場合には、最初の規則のアクションが実行されるというルールに従います。識別子用の規則の前に end やその他の予約語用の規則を配置すれば、予約語を確実に認識できます。
検索するパターンが別のパターンの接頭辞になっている場合には、また別の問題が発生する可能性があります。たとえば、上記の字句アナライザの例における最後の 2 つの規則は、> と >= を認識するようにデザインされています。
lex は、できる限り長い文字列と照合してその文字列用の規則を実行する、というルールに従います。テキストの一部に文字列 >= が含まれている場合には、スキャナは > で止まって > の規則を実行するのではなく、>= を認識して >= の規則を実行します。このルールによって、C プログラムの + と ++ が区別されます。
字句アナライザが、検索する文字列を超えて読み取る必要がある場合には、後方コンテキストを使用してください。その典型的な例が、FORTRAN の DO 文です。以下の DO 文の最初の 1 は、最初のコンマを読み取るまではインデックス k の初期値のように見えます。
DO 50 k = 1 , 20, 1
つまり、最初のコンマを読み取るまでは、この文は代入文のように見えます。
DO50k = 1
FORTRAN では空白はすべて無視されます。後ろに続く文字列が後方コンテキストであることを示すには、スラッシュ / を使用します。スラッシュはパターンの一部ではないため、この後方コンテキストは yytext[] には格納されません。
FORTRAN の DO 文を認識する規則は、以下のように記述できます。
DO/([ ]*[0-9]+[ ]*[a-zA-Z0-9]+=[a-zA-Z0-9]+,) { printf("found DO"); }
別バージョンの FORTRAN で識別子 (この例ではインデックス名) のサイズが制限されていても、この規則のように任意の長さのインデックス名を受け入れると、記述を簡素化することができます。後方コンテキストと類似した前方コンテキストの取り扱いについては、「開始条件」を参照してください。
lex では、特別な後方コンテキスト (行の終わり) を表す演算子として $ 記号を使用します。例として、行の終わりの空白文字とタブをすべて無視する規則を以下に示します。
[ ¥t]+$ ;
上記の例は、以下のように記述することもできます。
[ ¥t]+/¥n ;
パターンが行またはファイルの先頭にあるときにだけそのパターンと一致させるには、^ 演算子を使用します。たとえば、あるテキスト書式整形プログラムでは、空白文字以外の文字で行を開始する必要があるとします。その場合には、以下の規則を使用して、そのプログラムへの入力を検査できます。
^[ ] printf("error: remove leading blank");
左角括弧の内側に ^ 演算子がある場合との意味の違いに注意してください。