2013-04-15 2 views
5

私はコンパイラ構築のコースを取っています。現在私が実装している言語用のレクサーを書くのが私の現在の課題です。私は、レクサーが連結トークンを認識しなければならないという要件をどのように満たすかを理解できません。つまり、空白で区切られていないトークンです。例:文字列39ifは、数字39およびキーワードifとして認識されるはずです。同時に、不正な入力に遭遇した場合には、レクサーはexit(1)でなければならない。空白で区切られていないトークンをlex/flexで認識させる方法は?

コードの簡易版私が持っている:私はこの(または私の完全なバージョン)を実行し、それを入力39ifを渡すと、エラールールがマッチした、出力はERROR: 39if、です

%{ 
#include <stdio.h> 
%} 

%option main warn debug 

%% 

if  | 
then | 
else printf("keyword: %s\n", yytext); 

[[:digit:]]+ printf("number: %s\n", yytext); 

[[:alpha:]][[:alnum:]]*  printf("identifier: %s\n", yytext); 

[[:space:]]+ // skip whitespace 
[[:^space:]]+ { printf("ERROR: %s\n", yytext); exit(1); } 

%% 

(私は、入力として39 ifに入ったかのようにすなわち、同じ。)

number: 39 
keyword: if 

:私はそれがしたいのですがの場合、エラールールが数値ルールやキーワードルールよりも長い可能性のある入力と一致し、フレックスがそのルールを優先するという理由があります。つまり、私はこの状況をどのように解決するか考えていません。すべてのエラーでない入力を拒否する明示的な正規表現を書くことは実用的ではないようです。そして、レクサーエラーを処理するために "キャッチオール"ルールをどのように書くべきかわかりません。

UPDATE:私はちょうどキャッチオールルールが. { exit(1); }も作ることができると仮定が、私は「私は1行目に混乱しました」よりも、いくつかのよりよいデバッグ出力を取得したいのですが。

+0

a)簡易版を実行しましたか? b)それは何が間違っているのですか? –

+0

@IraBaxter申し訳ありませんが、最後の段落のスペキュレーションで失われている間、私のテストケースについて明示するのを忘れてしまったようです。答えは** a)**はいです。 ** b)**は、2つのトークンの代わりにレクサーエラーを報告します。 (私はそれらを質問に加えました。) – millimoose

+1

ああ。はい、あなたの "^スペース"ルールは、スペースのないシーケンスを食べるので、 "39if"を消費します。秘密:長いルールが安全に最初に来ない限り、正規表現が重なるルールは避けてください。あなたの場合、私は(私はlex-pertではない)置き換えるものを使用したいと思う:^スペース:それは "数字ではなく、文字ではなくスペースである"。 ... –

答えて

4

あなたはただ一つの「任意の」文字をフォールバックとしてマッチさせるべきです。解析中の行のどこにあるかに関する情報を取得する「標準的な」方法は、オプションを使用することですが、特にbisonを使用していない場合は、少し苦しいことがあります。例えば、あなた自身のI/O機能を指定する方法を手動で探す - - そこに他の方法の束がありますが、すべての周りの最も簡単な私見では開始条件を使用することです:

%x LEXING_ERROR 
%% 
// all your rules; the following *must* be at the end 
.     { BEGIN(LEXING_ERROR); yyless(1); } 
<LEXING_ERROR>.+ { fprintf(stderr, 
          "Invalid character '%c' found at line %d," 
          " just before '%s'\n", 
          *yytext, yylineno, yytext+1); 
        exit(1); 
        } 

注意:ルール内の空白が無視されていることを確認してください。パターン.+は、数字以外の少なくとも1つの改行されていない文字、つまり現在の行の最後まで一致します(これにより、フレックスはそれを遠くまで読み取るようになりますが、問題はありません)。 yyless(n)は、n文字で読み取りポインタをバックアップするので、.ルールが一致すると、その文字を再スキャンして半ば妥当なエラーメッセージ(うまくいけば)を生成します。 (あなたの入力がマルチバイトであるか奇妙な制御文字を持っていると本当に妥当ではないので、より慎重なコードを記述することができます)エラーが行の終わりにある場合は妥当ではないかもしれませんあなたはまた、より多くのコンテキストを取得し、より慎重な正規表現を書きたい、と多分前方の文字数が読み込ま制限することがあります。ここでは多くのオプション。)

%xBEGINについての詳細はフレックスマニュアルのstart conditionsを見上げて

+0

私は開始条件を読み上げましたが、本当に一緒に作品を置くことはできませんでした! – millimoose

+0

yytext [0]をの中のパーサーに返すほうがずっと簡単です。パーザのエラーリカバリを処理させます。開始状態は必要ありません。これにより、単一の特殊文字のすべての規則も削除されます。 – EJP

+0

@EJP:OPには、無効な入力に遭遇したときにレクサーが 'exit(1)'を実行しなければならないという要件の1つが具体的に記載されています。エラーリカバリの有無にかかわらず、パーサーがまったく存在しないということはありません。 – rici

関連する問題