プログラミング言語、正規表現、形式言語の関係は何ですか


25

この質問に対する答えをネットで探しましたが、私以外の誰もが暗黙のうちに答えを知っているようです。おそらくこれは、関心のある唯一の人がその主題について高等教育を受けた人だからです。一方、私は高校での宿題の最後に投げ込まれました。

私の質問は、プログラミング言語はどのくらい正確に正式言語に関連していますか?私が読むところはどこでも、「プログラミング言語の文法を定義するために形式言語が使用されている」という言葉があります。

今、私が集めたものから、正式な言語とは、特定の記号セット(言語のアルファベット)に適用される一連の生産規則です。これらの生産ルールは、次のような一連の変換を定義します。

b -> a

aaa->c

これは次のように適用できます。

abab->aaaa aaaa-> ca

補足として、正式な言語のアルファベットを{a、b、c}と定義すると、aとbは非終端であり、cは変換できないため終端です(間違っている場合は修正してください)それ)。

それを考えると、これはプログラミング言語にどのように当てはまるのでしょうか?また、正規表現を使用してテキスト形式の言語を解析し、文法が正しいことを確認することもよくあります。意味あり。その後、正規表現は正式な言語によって定義されると述べられています。正規表現は、正規表現を表す有限状態オートマトンがゴールポイントに到達したかどうかに応じて、(少なくとも私の経験では)trueまたはfalseを返します。私が見る限り、それは変換とは関係ありません*。

プログラム自体のコンパイルについては、正式な言語がコードを連続的に低レベルのコードに変換し、最終的にハードウェアが理解できる複雑なルールセットを介してアセンブリに到達できると思います。

だからそれは私の混乱した観点からのものです。おそらく、私が言ったことには根本的に間違っていることがたくさんあります。だから私は助けを求めています。


* (a|b)*b*c->trueプロダクションルールのようなものを検討しない限り、その場合、ルールには有限状態オートマトン(つまり、正規表現)が必要です。先ほど言ったように、これは意味がありません


2
正式な文法と正式な言語を混同しています文法は言語を記述し、書き換えルールのセットです。言語は、文法で記述された文字列のセットです。したがって、文法は正規表現に代わるものです。それは言語を記述する方法です。
reinierpost 14年

@reinierpostあなたは完全に正しいです、大学の講義ノートを読んだ後、私はこの情報のいくつかを手に入れました、私の間違いを見ます。
ツワンダー14年

私が始めたとき、私はあなたの混乱を共有しました。もちろん、文法も言語を形成し、正規表現も同様です。しかし、正式な言語理論は、言語の構文(形式)の記述方法の研究に専念しているため、通常、「言語」という用語は、記述対象ではなく、記述対象に使用されます。
reinierpost 14年

回答:


24

コードの解析に正規表現が使用されていると言った人は誰でも、偽情報を広めていました。古典的に(現代のコンパイラでこれがどの程度当てはまるかわかりません)、コードの構文解析(テキストから構文ツリーへのコードの変換)は2つの段階で構成されています。

  1. 字句解析:生のテキストを処理して、キーワード数値定数文字列識別子などのチャンクにします。これは、決定論的な有限オートマトン(DFA)に精神的に似た、ある種の有限状態マシンを使用して古典的に実装されています。

  2. パーサー:字句解析の後に実行し、生のテキストを注釈付きの構文ツリーに変換します。プログラミング言語の文法は(最初の近似では)コンテキストに依存せず(実際、さらに厳密なサブセットが必要です)、これにより、特定の効率的なアルゴリズムが構文化されたコードを構文木に解析できます。これは、特定の文字列が文脈自由文法に属しているかどうかを認識する問題にていますが、構文ツリーの形で証明も必要な点が異なります。

プログラミング言語の文法は、文脈自由文法として書かれており、この表現は、パーサージェネレーターが高速パーサーを構築するために使用します。単純な例では、非終端のSTATEMENTがあり、次にSTATEMENT IF-STATEMENTの形式のルールがあります。IF-STATEMENT if CONDITION then BLOCK endifなど(BLOCK STATEMENT | BLOCK; STATEMENTなど)。通常、これらの文法はBackus-Naur形式(BNF)で指定されます。

プログラミング言語の実際の仕様はコンテキストフリーではありません。たとえば、変数は多くの言語で宣言されていない場合は表示できません。厳密な型指定の言語では、文字列変数に整数を割り当てることができない場合があります。パーサーの仕事は、生のコードを処理しやすい形式に変換することだけです。

実際に解析ツリーを生成するのではなく、解析しながらコードを処理する再帰降下解析など、他のアプローチがあることに言及する必要があります。ツリーを生成することはありませんが、他のすべての点で、上記と同じレベルで動作します。


お返事ありがとうございます。確かにいくつかのことが解決されました。また、さらに多くの質問が寄せられました。それらを質問に追加するか、ここで質問する必要がありますか?
ツワンダー14年

5
@Zwander-実際、どちらでもありません。このサイトでは、質問ごとに1つの質問を作成してください。これはディスカッションフォーラムではありません。質問と回答のサイトであり、各質問を別々のスレッドに入れたいと考えています。この回答が新しい質問を提起した場合、そのフォローアップの質問を調査するために時間を費やし、標準のソースのいずれかで回答が見つからない場合は、新しい質問を投稿してください。(ただし、最初に標準リソースを確認してください。)
DW

1
@DW Gotcha、乾杯。
ツワンダー14年

3
言及する2つの段階の最初は、通常、正規表現を使用して行われます。通常、各トークンの形式は正規表現で指定されます。これらの正規表現は1つのDFAにコンパイルされ、DFAは実際のコードに適用されます。
カスペルド14年

2
@Zwander再帰降下解析は、1つの解析手法にすぎません。解析ツリーを生成する場合としない場合があります。一般に、解析アルゴリズムは、プログラムテキストに暗黙的に含まれる構文ツリーを探索するための計算戦略の開発に相当します。この構文/解析ツリーは、コンパイル戦略(ステージ数)に応じて、プロセスで明示的にされる場合とされない場合があります。ただし、必要なのは、計算構造で明示的に指定されているか暗黙的に残されているかにかかわらず、最終的に解析ツリーのボトムアップ探索が少なくとも1回行われることです。
babou 14年

12

これは、高校の宿題には重いものです。

Yuval Filmusの答えは本当に良いので、これは彼がしたポイントのいくつかを明確にするための補足的な答えです。

正式な言語は数学的な構成です。プログラミング言語でのそれらの使用は、多くの可能な使用の1つにすぎません。実際、言語学者のノアム・チョムスキーは、形式言語の初期の理論に多大な貢献をしました。彼はチョムスキー階層を発明しました、形式言語を通常のコンテキストフリーなどに分類します。形式言語は、英語などの自然言語の構文を記述するために言語学にも適用されます。実数のように考えてください。実数を使用して、ロサンゼルスからニューヨークまでの距離などの具体的なものと、円の円周と直径の比などの抽象的なものの両方を記述することができます。これらは実数とは独立して存在しますが、実数はそれらを説明するのに役立つシステムです。形式言語は、英語とPythonの両方を記述するのに役立つシステムです。どちらも類似した構造化形式を持っているからです。

a+b+c=da+b=dcabc たとえば、金額がドルである場合、方程式には意味があります。

古典的に、プログラミング言語には、字句文法と構文文法の2つの文法があります。字句文法は、文字、セミコロン、中括弧、括弧などの文字を扱います。通常は通常の文法なので、正規表現またはDFAまたはNFAで表現できます。(形式言語理論には、3つが同等の力を持っていることを示す証拠があります。つまり、同じ言語セットを受け入れます。)コンパイラーまたはインタープリターの字句作成フェーズは、通常の言語文法のミニインタープリターのようなものです。文法の規則を読み取り、それらの規則に従って、個々の文字をトークンにまとめます。たとえば、言語にifCのように見えるステートメントがある場合、レクサーは文字if1つのトークンにまとめますIF、開きかっこを探してトークンを出力しOPEN_PAREN、かっこの間のものを処理し、閉じかっこを見つけてaを出力しCLOSE_PARENます。字句解析プログラムがトークンの作成を完了すると、構文解析プログラムにトークンが渡され、トークンが実際にプログラミング言語の有効なステートメントを形成するかどうかが判断されます。したがってip a == b、Pythonで記述する場合、レクサーはどの種類のトークンでipあるかを推測するために最善を尽くし(おそらくほとんどのレクサーによって識別子として取得されます)、それをパーサーに渡します。その位置の識別子。

ab

Pythonのifステートメントの文法規則を見てみましょう。これがルールです:

if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

このルールは、レクサーから送信されたトークンの文字列がif-statementである場合、パーサーがどのように判断するかを示しています。単一引用符で囲まれた単語は、ソースコードにそのように表示される必要があるため、パーサーはプレーンな単語を探しますif。パーサーは、次のルールにいくつかのトークンを一致させようとしtestます:

test: or_test ['if' or_test 'else' test] | lambdef

test文法の他の規則に関して定義されています。testまた、定義に自分自身を含める方法にも注意してください。それは再帰的定義と呼ばれます。これは、通常の言語にはないコンテキストフリー言語の大きな力であり、ネストされたループのようなものをプログラミング言語の構文に定義できます。

パーサーがにいくつかのトークンtestを一致させることができた場合、コロンの一致を試みます。それが成功した場合、のルールを使用して、さらにいくつかのトークンを照合しようとしsuiteます。このセクション('elif' test ':' suite)*は、リテラルテキストの任意の数の繰り返しがありelif、その後に一致するものがtest続き、コロンが続き、その後に一致するものが続くことを意味しsuiteます。繰り返しをゼロにすることもできます。末尾のアスタリスクは「ゼロまたは必要な数」を意味します。

最後は['else' ':' suite]です。その部分は角括弧で囲まれています。つまり、ゼロまたは1つだけ持つことができますが、それ以上はありません。これに一致するには、パーサーはリテラルテキストelse、コロン、aの順に一致する必要がありますsuite。のルールは次のsuiteとおりです。

suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

基本的に、Cライクな言語のブロックです。Pythonは、レクサー出力平均物事に改行とインデントを使用しているためNEWLINEINDENTと、DEDENTコードが起動開始新しい行が、インデントするパーサを伝えるために、トークン、およびそれがインデントの外側のレベルに戻ったところ。

これらの一致の試みのいずれかが失敗すると、パーサーはエラーにフラグを立てて停止します。プログラム全体の構文解析が成功した場合、パーサーは通常、Yuvalが回答で説明した構文解析ツリーと、場合によっては意味情報を格納するシンボルテーブルおよびその他のデータ構造を構築します。言語が静的に型付けされている場合、コンパイラは解析ツリーをたどって型エラーを探します。また、解析ツリーをたどって、実際に実行される低レベルのコード(アセンブリ言語、Javaバイトコード、.Net中間言語、または同様のもの)を生成します。

練習として、あなたがよく知っているプログラミング言語の文法(もう一度、PythonJava、そしてC#JavascriptC)を使用して、maybe x = a + b;やなどの単純なものを手動で解析することをお勧めしますif (True): print("Yay!")。もっとシンプルなものを探しているなら、JSONの素晴らしい文法もあります。これは基本的にJavascriptのオブジェクトリテラル(など{'a': 1, 'b': 2})の構文のみをカバーしています。幸運なことに、これは脳を曲げるようなものですが、あなたが狂った締め切りに間に合わないとき、それは本当に興味深いことが判明しました。


ここに「ありがとう」を投稿するつもりはないことは知っていますが、このすべてを時間をかけて説明してくれてありがとう。「これは、高校の宿題には重いものです。」課題の目的は、ざっと目を通し、正規表現について話すことですが、熱心なコンピューターサイエンスの学生として、全体像を知りたいと思いました。トピック全体が魅力的です。
ツワンダー14年

1
@Zwander私は大学を卒業したばかりで、私の選択科目のほとんどはこのようなものでした。私は完全に混乱しているが、完全に夢中になったことを覚えています。また、このブログで言及されているコンパイラー設計に関する論文、またはMichael SipserとJohn C. Martin の著書 『Introduction to the Theory of Computation』言語と計算理論の紹介が好きかもしれません。Amazonで安価な中古コピーを見つけることができます。どちらも、公式言語理論を実現するのと同じくらい簡単にします。
tsleyson 14年

10

一言で言えば

プログラミング言語は、プログラムを文字列として表す構文と、プログラムの意図する意味であるセマンティクスで構成されます。

形式言語は意味のない構文です。通常、これらの文字列に意味を付けることなく、形式的に定義された文字列のセットの構造を調べることを目的としています。

正規表現およびその他の形式(コンテキストフリー文法など)は、プログラミングおよび自然言語の構文コンポーネントとして使用される形式言語を定義するために使用されます。つまり、構造化された方法で文を表します。他のメカニズムを使用して、その構造をプログラミング言語のセマンティクスと関連付けます。

ここでは、特に自然言語に関して、かなり簡略化されています。

もっと詳細に

あなたの質問に答えるには、最初から始めなければなりません。通常の意味での言語は、非公式には、情報やアイデアを伝える手段です。言語では、通常、構文とセマンティクスを区別します。セマンティクスは、あなたが話したい/書きたいものです。伝えたい情報。構文は、それを伝えるために使用する手段です。つまり、人々間で交換できる従来の表現であり、現在は人々とデバイス間、またはデバイス(コンピューター)間でも交換できます。

通常、dog犬のアイデアを伝えるためにこの言葉を使用します。単語dogは3文字または同等の音で構成されており、ある種の動物を表すことを目的としています。重要な考え方は、コミュニケーションは、伝えられるものの表現を通じて行われるということです。通常、表現構造は構文と呼ばれ、表現されるものはセマンティクスと呼ばれます。これは、プログラミング言語だけでなく、自然言語にもほぼ当てはまります。

単語は、多かれ少なかれ基本的なセマンティック概念を表すための構文エンティティです。しかし、これらの基本的な概念は、より複雑な意味を与えるためにさまざまな方法でまとめる必要があります。私たちthe dogは特定の犬を意味することをthe dog bites the cat伝え、より複雑なアイデアを伝えるために書き ます。しかし、犬と猫のどちらが実際にもう一方を噛んでいるかを知ることができるように、言葉の構成方法はルールによって修正する必要があります。

そのsentence -> subject verb complementため、文に一致し、各部分に関連付けられたアイデアがどのように明確化されるかを示すルールがあります。これらの規則は、メッセージの表現がどのように編成されるかを教えてくれるため、構文規則です。subject自体はルールによって定義することができますsubject -> article nounように、と。

2バツ+1=23バツ123

equation -> expression "=" expression  
expression -> expression "+" expression 
expression -> number

プログラミング言語の構造は同じです。プログラミング言語は、解決すべき問題、定理の証明、または動物間の友好関係を表すのではなく、実行する計算を表すことに意味的に特化しています。しかし、それが主な違いです。

構文で使用される表現は、通常、文字列、または話し言葉の音の文字列です。セマンティクスは通常、抽象的な領域に属しているか、現実に属している可能性がありますが、それでも思考プロセスやデバイスの動作領域に抽象化されています。通信では、情報/アイデアを構文にエンコードし、受信者が送信およびデコードします。その結果は、受信者によって何らかの方法で解釈されます。

したがって、この言語で見られるのは、ほとんど構文とその構造です。上記の例は、構文文字列とその構造編成を定義する最も一般的な方法の1つにすぎません。他にもあります。特定の言語では、一部の文字列に構造を割り当てることができ、その言語に属すると言われますが、そうでない文字列もあります。

言葉についても同じことが言えます。いくつかの文字(または音)のシーケンスは正当な単語ですが、他のシーケンスはそうではありません。

形式言語は意味論のない単なる構文です。アルファベットの基本要素を使用して、構築可能なシーケンスを一連のルールで定義します。ルールは非常に多様で、時には複雑になる場合があります。しかし、正式な言語は、自然言語であれプログラミング言語であれ、言語コミュニケーションを超えた多くの数学的な目的に使用されます。言語の文字列を定義する一連の規則は、文法と呼ばれます。しかし、言語を定義する方法は他にもたくさんあります。

実際には、言語は2つのレベルで構成されています。字句レベルは、文字のアルファベットから構成される単語を定義します。構文レベルは、文、または単語のアルファベット(より正確には単語ファミリのアルファベットで構成されているため、有限のアルファベットのままである)から構成されるプログラムを定義します。これは必然的にいくらか単純化されます。

単語の構造はほとんどの言語(プログラミングまたは自然)でかなり単純であるため、通常、最も単純な形式言語と見なされるものである通常言語で定義されます。これらは正規表現(regexp)で定義でき、有限状態オートマトンと呼ばれるプログラムされたデバイスでかなり簡単に識別できます。プログラミング言語の場合、単語の例は、識別子、整数、文字列、実数、if またはなどの予約語repeat、句読点記号、または開き括弧です。単語ファミリの例は、識別子、文字列、整数です。

構文レベルは通常、少し複雑な形式の言語、つまり単語をアルファベットとして使用するコンテキストフリー言語によって定義されます。上で見た規則は、自然言語の文脈自由な規則です。プログラミング言語の場合、ルールは次のとおりです。

statement -> assignment
statement -> loop
loop ->  "while" expression "do" statement
assignment -> "identifier" "=" expression
expression -> "identifier"
expression -> "integer"
expression -> expression "operator" expression

このようなルールを使用すると、次のように記述できます。

while aaa /= bbb do aaa = aaa + bbb / 6 これは声明です。

そして、その生成方法は、解析ツリーまたは構文ツリーと呼ばれるツリー構造で表すことができます(ここでは完全ではありません)。

                          statement
                              |
            _______________  loop _______________
           /      /                 \            \
      "while" expression           "do"       statement
       __________|_________                       |
      /          |         \                  assignment
 expression "operator" expression          _______|_______
     |           |          |             /       |       \
"identifier"   "/="   "identifier" "identifier"  "="   expression
     |                      |            |                 |
    aaa                    bbb          aaa             ... ...

規則の左側に表示される名前は非終端記号と呼ばれますが、単語は言語のアルファベット順(字句レベルより上)であるため、終端記号とも呼ばれます。非終端記号は、プログラムを構成するために使用できるさまざまな構文構造を表します。

このようなルールはコンテキストフリーと呼ばれます。非終端記号は、出現するコンテキストに関係なく、対応するルールを使用して任意に置き換えることができるためです。言語を定義する一連のルールは、コンテキストフリー文法と呼ばれます。

実際には、識別子を最初に宣言する必要がある場合、または式が型の制限を満たす必要がある場合、それに制限があります。しかし、そのような制限は、構文的なものではなく、意味的なものと見なされる場合があります。実際、一部の専門家は静的セマンティクスと呼ばれるものにそれらを配置します 。

任意の文、任意のプログラムが与えられると、その文の意味は、この文の解析ツリーによって与えられた構造を分析することによって抽出されます。そのため、プログラムが与えられたときに、プログラムに対応するツリー構造を回復できるパーサーと呼ばれるアルゴリズムを開発することが非常に重要です。

パーサーの前には、単語を認識し、それらが属するファミリーを判別する字句アナライザーがあります。次に、基礎となるツリー構造を取得するパーサーに一連の単語または語彙要素が与えられます。この構造から、コンパイラーはコードを生成する方法を決定できます。これは、コンパイラー側のプログラム処理のセマンティック部分です。

コンパイラのパーサーは、実際には解析ツリーに対応するデータ構造を構築し、それをコンパイルプロセスの後の段階に渡すことができますが、そうする必要はありません。解析アルゴリズムの実行は、プログラムテキストに暗黙的な構文ツリーを探索するための計算戦略の開発に相当します。この構文/解析ツリーは、コンパイル戦略(ステージ数)に応じて、プロセスで明示的にされる場合とされない場合があります。ただし、必要なのは、計算構造で明示的に指定されているか、暗黙的に残されているかにかかわらず、最終的に解析ツリーのボトムアップ探索が少なくとも1回行われることです。

その理由は、直感的には、構文木構造に関連付けられたセマンティクスを定義する標準の正式な方法は、準同型と呼ばれるものを使用するためです。大きな言葉を恐れないでください。アイデアは、単に全体の意味がパーツの意味から構築され、それらを接続する演算子に基づいて考慮することです

たとえば、文the dog bites the catはルールを使用して分析できますsentence -> subject verb complement。3つのサブツリーの意味を知ることsubjectverbおよびcomplement、それらを構成するルールは、対象者がアクションをやって、そして猫がかまされたものであるとされていることを教えてくれる。

これは直感的な説明にすぎませんが、形式化できます。セマンティクスは、構成要素から上向きに構築されます。しかし、これは多くの複雑さを隠しています。

コンパイラの内部動作は、いくつかの段階に分解できます。実際のコンパイラは、中間表現を使用して段階的に動作する場合があります。また、いくつかの段階をマージする場合があります。これは、使用する技術と、手元の言語のコンパイルの複雑さに依存します。


すごい、とても助かりました。私は正規表現がトークン化プロセスで使用されることを理解しています(たとえば、文字列リテラルは"[^"]*"最も単純な形式で定義でき、エスケープ文字などを無視します)が、構文ツリーの作成にも使用されます(プログラミング言語の観点から)?私は、有限状態オートマトンが定義されているように、定義によって有限ではないと思います。構文ツリーは、単一のifステートメントであっても、ネストのために理論的には無限になります。したがって、有限状態オートマトンである正規表現は、構文ツリーを生成する目的には使用できません。
ツワンダー14年

@Zwander thx 4編集-正規表現の例は正しいです(いくつか例を示したはずです)。ところで、正規表現も言語であり、一連の文字列の世界で独自のセマンティクスを持ち、コンテキストフリー(CF)構文を備えています。少なくともプログラミング言語では、言語文字列のトークン化にのみ使用されます。通常、拡張BNF(EBNF)の省略形を除き、構文ツリーに使用されるより大きな構文の定義には使用されません。何らかの形で正規表現をより複雑な形式に追加しても、ほとんどの場合、表現力は変わりません。無限大についてのあなたの発言はまったく正しくありません。次のコメントを参照してください。
babou

@Zwanderすべての形式(形式言語)は有限に記述されています。それは基本的な仮説です。たとえば、無限の数のルールを持つCF文法に興味がある場合でも、その無限のルールの有限記述を提供する必要があります。また、無限はあなたにトリックをかけます(そのためのスペースはありません)。if文は無制限(任意の大きさ)が、常に有限です。有限に定義された無限ifはa whileです。CFとレギュラーの違いは、レギュラーはそうではないが、CFはネストを制御/許可する(つまり、括弧付けする)ことです。ただし、どちらも有限に記述されており、無制限の文字列を許可します。
babou

1
形式主義@Zwander任意整形文(プログラム)を表す、しかしすることができなければならないだけ十分に形成された文章。簡単に言えば、FSAは無制限にカウントできません。そのため、閉じられるべき括弧がいくつ開かれたかを知ることも、2種類の括弧を適切にネストすることもできません。多くの言語構造には、「隠された」括弧があります。これは単に構文チェックの問題ではなく、主に適切なツリー構造を表現および構築できず、そこからセマンティクスを導出できないことを意味します。適切なツリー構造を回復するには、カウントを実行する必要があります。
babou

1
AB+3×C

2

大きな違いがあります。その中でも最も重要なのは、実際のプログラミング言語の構文解析はすべて構文エラーの処理に関するものだということです。正式な言語では、「それは言語ではない」と言うだけですが、それはあまり役に立たないというコンパイラーです。何が悪いのかを教えてくれるはずです。より多くのエラーを報告します。多くの研究(および実装の努力)がその中に入ります。そのため、真/偽の結果についてはあまり気にせず、入力の構造を分析するだけです。そこで正式な言語がツールとして使用され、多くの重複がありますが、実際には別の問題を解決しています。

また、ほとんどの言語では、文法で特定のことを実施しないように選択されています。たとえば、「変数が宣言されていない場合、変数は表示できません」などと言います。これは通常、パーサーによって完全に無視され、そのようなものを調べ、コンテキストの自由度などの考慮事項の影響を受けない別の分析(セマンティック分析)で捕まえられるものです。しかし、常にではありません-たとえば、Cを解析するために、レクサーハックがよく使用されます。C++は、いくつかの深刻なセマンティック分析を同時に実行しないと解析できない言語の有名な例です)。単純な言語では分割される傾向がありますが、その方が簡単です。


1

正式な言語は一連の単語です-単語はいくつかのアルファベットからの記号の文字列です。

これは、生産規則と形式言語の結合が強すぎることを意味します。正式な言語が制作規則であることは正しくありません。むしろ、生産規則は形式言語を定義します。正式な言語とは、プロダクションルールで生成できる単語です。(これには、正式な言語がプロダクションルールで定義できる種類であることが必要です。たとえば、通常の言語は文脈自由文法で定義できます)

そのため、式に対応する通常の言語(a|b)*c*dはプロダクションルールによって定義されます。

S->ACd
A->
A->aA
A->bA
C->
C->cC

これらのプロダクションルールが開始記号Sから生成する単語は、正規表現が受け入れる文字列です。


0

正規表現とプログラミング言語の間には、セマンティクスに関係する別の関係があります。命令型言語の基本的な制御構造は、順次構成(Aを実行してからBを実行)、選択(AまたはBを実行)、および反復(繰り返しAを実行)です。

動作を結合する同じ3つの方法は、正規表現にあります。サブルーチン呼び出しをスローすると、EBNFに類似しています。

したがって、正規表現の代数とコマンドの代数の間には多くの類似点があります。これについては、「3つの計算の統一」でダイクストラが詳しく調べています。これは、質問への答えを提供するミルナーのCCSの基礎でもあります。並列性を追加するとどうなるでしょうか。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.