From e79338ba7ba2a5e840def754a0c5bd7b6043fae7 Mon Sep 17 00:00:00 2001 From: Kota Mizushima Date: Tue, 17 Dec 2024 19:58:49 +0900 Subject: [PATCH] =?UTF-8?q?=E6=9B=B8=E7=B1=8D=E3=81=AE=E7=AB=A0=E3=82=92?= =?UTF-8?q?=E5=86=8D=E6=A7=8B=E6=88=90=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2章の内容を2章と3章に分割 - 3章以降を1章ずつ後ろにずらす(予定) --- honkit/chapter1.md | 2 +- honkit/chapter2.md | 115 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/honkit/chapter1.md b/honkit/chapter1.md index 345864f..c9f91ab 100755 --- a/honkit/chapter1.md +++ b/honkit/chapter1.md @@ -108,4 +108,4 @@ x = 1 2025年xx月dd日、自室にて。水島宏太 -[^1] 「コンパイラ 第2版: 原理・技法・ツール」のこと。コンパイラ開発者にとってバイブルとも言われる本である +[^1] 「コンパイラ 第2版: 原理・技法・ツール」のこと。コンパイラ開発者にとってバイブルとも言われる本である \ No newline at end of file diff --git a/honkit/chapter2.md b/honkit/chapter2.md index ce2ddc8..d373b0c 100755 --- a/honkit/chapter2.md +++ b/honkit/chapter2.md @@ -1,6 +1,113 @@ -# 2. 身近な構文解析器 +# 2. 身近な構文解析 + +この章からいよいよ構文解析についての説明を始めたいと思います。とはいっても本書を手に取った皆様は構文解析についてまだ馴染みがないかと思います。そこで、まずは第1章でみたような算術式の構文解析を例にして、構文解析の基本について学ぶことにしましょう。 + +## 2.1 算術式の文法 + +ただ「算術式」といっただけだと人によってかなりイメージするものが異なります。本書では以下の条件を満たすものを算術式とします。 + +- 四則演算が使える + - 足し算は`x + y` + - 引き算は`x + y` + - 掛け算は`x * y` + - 割り算は`x / y` +- 優先順位は掛け算・割り算が高く、足し算・引き算が低い + - たとえば、`1 + 2 * 3`は`1 + (2 * 3)`と解釈される +- 同じ優先順位の演算子は左から右に結びつく + - たとえば、`1 + 2 - 3`は`(1 + 2) - 3`と解釈される +- 値は整数のみ + - たとえば、`1 + 2.0`のような式はエラーになる +- 式の優先順位を変えるために括弧を使うことができる + - たとえば、`(1 + 2) * 3`は`3 * 3`と解釈される +- 式の要素間にあるスペースは無視される + - たとえば、`1+2`は`1 + 2`と同じ + +この定義に従う算術式には以下のようなものが含まれます。 + +```text +1 + 2 * 3 +(1 + 2) * 3 +3 * (1 + 2) +12 / 3 +1 + 3 * 4 / 2 +``` + +普段、皆さんは何かしらのプログラミング言語を使ってプログラムを書いているはずですから、上のような算術式は馴染みが深いはずです。 + +しかし、上のような日本語を使った定義だけでは算術式の文法を表現するのには不十分です。たとえば「式の要素間にあるスペースは無視される」という言葉だけでは、`10`と`1 0`を区別することができません。優先順位についても感覚的にはわかるものの、やはり定義としては曖昧です。式の優先順位を変えるために括弧を使えるという表現も、直感にはあっているものの現実の文法を表現するには不十分です。 + +もちろん、日本語でより詳しく記述して曖昧さを少なくしていくこともできますが、いたずらに長くなるだけです。それよりも、文法を表現するための文法である形式文法(Formal Grammar)を使って、算術式の文法を表現することが一般的です。形式文法というと何かしらとても難しいもののように感じられますが、実際には簡単なものです。次節では形式文法の一つであり、もっともメジャーな表記法であるBNF(Backus-Naur Form)を使って、算術式の文法を表現してみましょう。 + +```bnf + +形式文法の一つであるBNF(Backus-Naur Form)を使って、算術式の文法を表現してみましょう。 + +```bnf + + +構文解析については色々な立場があることを第1章で述べましたが、ここでは第1章で述べた以下の考え方を採用します。 + +> 入力文字列を引数にとって、文法に沿っているならば抽象構文木を、そうでなければエラーを返す関数を構文解析とみなす + +このよう + +考え方を採用します。つまり、以下のような関数(メソッド)`parse(String input)`によって行われるものが構文解析であり、その結果返される`ParseResult`が構文解析の結果を表します。 + +```java +sealed interface ParseResult permits ParseResult.Success, ParseResult.Failure { + record Success(Tree ast) implements ParseResult {} + record Failure(String errorMessage) implements ParseResult {} +} +ParseResult parse(String input); +``` + +JSON(JavaScript Object Notation)を例にして、典型的な構文解析について説明していきます。 +## 2.2 JSONとBNF + + プログラミング言語の文法自体を表現する文法(メタ文法といいます)の一つに、BNFがあります。BNFは、プログラミング言語の文法をはじめ、インターネット上でのメッセージ交換フォーマットなど、様々な文法を表現するのに使われています。とはえ、本書の読者の方にはBNFに馴染みのない方もいると思うので、まず次の節で簡単にBNFについて説明した後、JSONを表現するBNFについて説明します。なお、本書ではISO/IEC 14977で仕様が策定されたEBNFの事を指してBNFと呼ぶことにします。BNFは歴史的に、かなり多くの方言があり、どの記法を使うか事前に説明しておかないと読みづらいためです。 + +### 2.2.1 BNF + +BNFは、正式にはBackus-Naur Form(バッカス・ナウア記法)と言います。Fortranの開発者でもある、John Backus(ジョン・バッカス)らが開発した記法であるBNFは、「プログラミング言語」そのものの文法を記述するために開発されました。基本情報技術者試験でも出題されるので、ひょっとしたらそこで知った方もおられるかもしれません。 + +とはいっても、これだけではチンプンカンプンかもしれませんので具体例を見て行きましょう。 + +たとえば、Java言語のローカル変数を宣言するプログラムの断片を考えてみると、以下のようになるでしょう。 + +```java +// int型の変数x1を宣言して初期値を与えない +int x1; +// int型の変数x2を宣言して1を代入 +int x2 = 1; +// String型の変数y1を宣言して初期値を与えない +String y1; +// String型の変数y2を宣言して"Hello, World"を代入 +String y2 = "Hello, World"; +// Double型の変数z1を宣言して初期値を与えない +Double z1; +// Double型の変数z2を宣言して1.0を代入 +Double z2 = 1.0; +``` + +ローカル変数の宣言をよく見て行くと、以下のような形をしていることがわかります。 + +```text +型 変数名 ('=' 初期値)? ';' +``` + +`(E)?`は`E`が省略可能であることを示しています。`'='`はその記号自体がでてくることを示しています。 + +変数宣言の最初にはまず、型名が来て、その次に変数名、続いて省略可能な初期値が来ることを示しています。ローカル変数宣言はセミコロンで終わることも示しています。このように、プログラミング言語の文法には一定のルールがあり、それを曖昧さが無い形で解釈できると便利です。 + +このようなニーズに答えるのが、BNFです。 + +先ほどの文法をBNFで表現すると以下のようになります。 + +```bnf +local_variable_declaration = type_name identifier ('=' expression)? ';' + +このような、`=`で分かれた内の左側を規則名と呼び、右側を本体と呼びます。また、本体と非終端記号を合わせて規則と呼びます。本書では、BNFを多用していくので、慣れていくようにしてください。 - この章から、構文解析についての説明を始めたいと思います。この本を読んでいる読者の方は何らかの形で「構文解析器」または「構文解析」という用語に触れたことがあるのではないかと思います。この用語が意味するものはいったんおいておくとして、この章では、JSON(JavaScript Object Notation)を例にして、典型的な構文解析について説明していきます。 ## 2.1 JSON(JavaScript Object Notation)の定義 @@ -121,7 +228,7 @@ false  次の節では、このJSONの**文法**が、どのような形で表現できるかについて見ていきます。 -## 2.2 JSONとBNは +## 2.2 JSONとBNF  プログラミング言語の文法自体を表現する文法(メタ文法といいます)の一つに、BNFがあります。BNFは、プログラミング言語の文法をはじめ、インターネット上でのメッセージ交換フォーマットなど、様々な文法を表現するのに使われています。とはえ、本書の読者の方にはBNFに馴染みのない方もいると思うので、まず次の節で簡単にBNFについて説明した後、JSONを表現するBNFについて説明します。なお、本書ではISO/IEC 14977で仕様が策定されたEBNFの事を指してBNFと呼ぶことにします。BNFは歴史的に、かなり多くの方言があり、どの記法を使うか事前に説明しておかないと読みづらいためです。 @@ -225,7 +332,7 @@ json = object; object = LBRACE RBRACE | LBRACE pair {COMMA pair} RBRACE; ``` -EBNFにおいて`{}`で囲まれたものは、その中の要素が0回以上繰り返して出現することを示しています。また、`pair`の定義はのちほど出てきますので心配しないでください。 +EBNFにおいて`{}`で囲まれたものは、その中の要素が0回以上繰り返して出現することを示しています。`pair`の定義はのちほど出てきますので心配しないでください。 この規則によって`object`は