Rustでインタプリタを作ってみる(日記): 2日目
達成すること
- 構文解析を理解、実装の一歩を書く
- lexer.rs, token.rsを作る
- 最終Output
{Type:let Literal:let}
{Type:IDENT Literal:add}
{Type:= Literal:=}
{Type:fn Literal:fn}
{Type:( Literal:(}
{Type:IDENT Literal:x}
{Type:, Literal:,}
{Type:IDENT Literal:y}
{Type:) Literal:)}
{Type:{ Literal:{}
{Type:IDENT Literal:x}
{Type:+ Literal:+}
{Type:IDENT Literal:y}
{Type:; Literal:;}
{Type:} Literal:}}
{Type:; Literal:;}
アウトプット
文字列を受け取る→字句を定義→定義した字句に分解、スペース処理
https://mermaid-js.github.io/mermaid/#/classDiagram
-
設計図
-
文字、数字、など自由な入力を字句ごとに分けたあとなんのタイプ;kindか判定する関数を作る必要がある。
- { } ; : ( ) , etc などは決まった形だからnexttoken()内で簡単にmatch処理していいが、それ以外の自由な入力が。。。という話
-
isLetter()&readLetter()
-
isNumber()& readNumber()
--- 最後の処理
read eval print loop : REPL
fn Start {
// scan input
lexer::new()
while tokenkind == EOF{
printf(token)
}
}
- 変更点
Start()はlexer::newするのでlexerクラス内のメソッドにすべきではない。
repl.rsを作った。
https://doc.rust-lang.org/reference/tokens.html#ascii-escapes
http://www3.nit.ac.jp/~tamura/ex2/ascii.html
↑ASCII表など
最終結果
疑問
設計の疑問点
struct Lexerにて、
return Token::new(Token::get_keyword(&literal), literal);
これでいいのか
→共依存になるのでだめ。get_keywordはlexer.rs側で内部関数として定義すべき。
TokenがStirngであるのでそこのパフォーマンスはどうなのか?
Self::structfn(&self.field)みたいなのと、
self.structfn() どっちがいいんだろう。(後者は関数内でself.fieldにアクセスしている)
振り返り
アーキテクチャを先に大雑把に決めないと何も進まない
依存関係を考えてどこにfnを定義するか決めるべき。
概念理解 → 概念を具体的にしてモジュール化 → 設計図書く → (処理のフローをざっくり書いた方がよさげ?fnの具体性も上がるし) → 実際に書く → 適宜修正
-todo
- test とエラー処理書いてない。
- 何入れてもirregalになる…何がダメなのか全くわからん。→new でself.chに0をセットしてそれをinputの一文字目に変えることなくmatchしていた。new関数の中に一回read_step_charを入れることで解決。
リポジトリ
Discussion