2017-01-13 4 views
3

tl; dr:私はnomを使用して先読みを必要とする文書パーサーの例やドキュメントを見つけるのに苦労しています。nomを使用して先読みが必要なテキストを解析する

ロングバージョン

私は6502アセンブリを解析するためにNOMを使用しています。私は、さまざまなアドレッシングモードを解析できるパーサを作成することに苦労しています。 XXXは3文字のニーモニックであるとAMがオペランドである

XXX AM

:任意の所与のオペコードは、次の形式を持っています。オペランドは多くの形式をとることができ、「アドレッシングモード」と呼ばれます。私は、オペランドの列挙型、アドレッシングモードの列挙型、およびこれらの値を含むタプル構造体OpCodeを定義しました。これは最終的に解析時に返される結果です。

アドレッシングモードは完全に省略することができます。この場合、アドレッシングモードはImpliedです。リテラル値はAで、これはAccumulatorアドレッシングモードです。

アドレッシングモードの多くはメモリ位置を参照しています。これらのアドレッシングモードは解析するのに苦労しています。特に、アドレッシングモードが$00の形式で単一バイトを指定する場合、それはZeroPageアドレッシングモードであり、$0000の形式の2バイトを指定するオペランドはAbsoluteアドレッシングモードです。問題を複雑にし、$00,Xの形でこれらのアドレッシングモードのインデックス化変異体、$00,Y$0000,Xなど

があり、そのすべての開始値を解析するために正しい方法を示します既存のテキストパーサのいずれかの良い例があります同様に(​​)、どのようにそれらが終わるかによって区別されますか? nomのドキュメントはあまり包括的ではありません。私が見つけた最良の例はINIパーサです。これは達成しようとしているほど複雑なことをしていません。私もsynソースコードを見てきましたが、それはカスタムマクロをたくさん使用しており、かなり複雑な獣ですから、学ぶのは難しいです。

+0

[私が書いた6502エミュレータ、アセンブラ、逆アセンブラの箱](https://github.com/simon-whitehead/rs6502)はこれを手で動かします。おそらく、Rustの解析の最良の例ではありませんが、それは確かにそれを行うことができます(注:私はまだこれをクリーンアップ段階にしていますが、今は休日が進行しています。アセンブラフォルダはすべてどこにあるのですか?非常に明示的でかなりネストされていますが、何かに役立つかもしれませんか?注 - 私は先を見ていません。私はちょうどそれをトークン化し、私が行くようにそれを把握する。だから私はあなたが何をしているのか分からないのですか? –

+0

私はnomaを使ってやってみようとしていること、あるいは少なくとも私が現在それに近づいていることにlookaheadが必要であると思います。好奇心のために、あなたのアセンブラは自己完結型ですか?私は本当に簡単なものを探しています。私が書いているNESエミュレータの単体テストを作成するのに使うことができます。 –

+0

この文脈で私のために「自己完結型」を定義しなければなりません。それは自己完結しているという意味で、そのすべてがRustで書かれています。そのファイルは1ファイルではないという意味で自己完結型ではなく、 'lexer.rs'、' parser.rs'、 'token.rs'、' assembler.rs'ファイルの型に依存しています。あなたが依存関係として使用して使用するのに十分単純でなければなりません - あなたの特定のユースケースを知らなくてもそれを言うことができます。アセンブラは、6502ニーモニックコードを入力として解析するとき、(現在)非常に制限されています。たとえば、いくつかのアセンブラーのように空想的なマクロや条件付きの構造体はありません。 –

答えて

2

これを行う方法の1つは、alt!()マクロです。

アイデアには、それぞれの選択肢を順番に試すパーサがあります。だから、あなたはすでに個別アドレッシングモードのそれぞれについて、パーサを持っている場合、あなたがそれらのいずれかのためのパーサにそれらを組み合わせることができます。

// The sub-parsers all return Operand too. 
named!(parse_operand<&str, Operand>, 
    alt!(parse_absolute_indexed | 
     parse_absolute | 
     parse_zeropage_indexed | 
     parse_zeropage | 
     parse_implied)); 

いくつかの注意:

  • 順序が重要であるかもしれません。私はparse_absolute_indexedの後にparse_absoluteを置いた。前者はオペランドの最初の部分と一致し、早すぎるので返す。
  • バリアントは、各サブパーサーにマッチする行末(該当する場合はコメントを含む)を含めることです。その後、早い段階で一致することはできませんでした。
  • 改行などのパターンを終了するバイト/文字なしで入力の最後まで解析する場合は、alt!()の代わりにalt_complete!()を使用する必要があります。その理由は、ADD $00と一致させると、ADD $0000と一致する可能性のあるパーサは、より多くの入力が到着した場合でも一致すると仮定しなければならず、alt!()は次のケ​​ースにスキップしません。 alt_complete!()を使用するか、complete!()に内部マッチャをラップすると、不完全なマッチは不一致であると言われます。

パーサが非常に複雑された場合、それは例えば由緒あるyaccによって生成されたパーサに比べて(順番に解析し、それぞれをしようとして)、余分な仕事をしている意味するかもしれませんが、私はそれが、この場合の問題だとは思いません。

+1

私が注意しなければならないことの一つは、あなたが述べたようにパーサを正しく並べる間に 'alt_complete! 'を使わなければならないということです。 'alt_complete'がなければ、' IResult :: Incomplete'でメモリアドレス指定モードのいくつかで解析が失敗します。 –

+0

ありがとうございます。私はメモを追加しました。それが正しいと思わないかどうか私に教えてください! –

関連する問題