入力をトークン化する
テキストをトークンに変換します。
「入力をトークン化する」はCoddyKit上の無料C Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
Tokenizerとは
インタープリタはまず、生のテキストをトークン、つまり意味を持つ最小単位に変換します。文字列 3 + 4 * 2 に対して、Tokenizer(またはlexer)は数値と演算子を生成します。
この段階で空白を取り除き、文字のまとまりを分類するため、パーサーは生のバイトを扱わずに済みます。
トークン型
各トークンをenumタグとペイロードで表現します。数値は整数値を持ち、演算子と括弧には種類だけが必要です。
値を構造体内に保持しておくと、後でソースを再スキャンせずに済みます。
typedef enum {
TOK_NUM, TOK_PLUS, TOK_MINUS,
TOK_STAR, TOK_SLASH,
TOK_LPAREN, TOK_RPAREN, TOK_EOF
} TokKind;
typedef struct {
TokKind kind;
int value; /* used when kind == TOK_NUM */
} Token;スキャン位置
lexerはカーソルポインタを使ってソースを走査します。小さなヘルパー関数で、現在の文字を消費せずに確認できます。末尾では '\0' を返します。
ポインタ演算によって、スキャナを高速かつ単純に保てます。
static const char *src;
static char peek(void) {
return *src;
}
static char advance(void) {
return *src++;
}空白のスキップ
トークンを読み取る前に、スペースとタブを破棄します。<ctype.h> の標準関数 isspace が、あらゆる空白文字を処理します。
ここでは改行も空白として扱うため、式を複数行にまたがって記述できます。
#include <ctype.h>
static void skip_ws(void) {
while (isspace((unsigned char)peek()))
advance();
}数値の字句解析
カーソルが数字の上にある場合、連続する数字を整数にまとめます。10倍して各数字を加えることで、左から右へ値を構築します。
ループは最初の数字以外の文字で停止し、カーソルは次のトークンを読み取れる位置に残ります。
static int lex_number(void) {
int n = 0;
while (isdigit((unsigned char)peek())) {
n = n * 10 + (advance() - '0');
}
return n;
}The next_token関数
中心となる処理では、空白をスキップしてから現在の文字に応じて処理を振り分けます。数字は TOK_NUM になり、各演算子はそれぞれの種類に対応します。
終端NULに到達すると、停止の合図である TOK_EOF が生成されます。
static Token next_token(void) {
skip_ws();
char c = peek();
if (c == '\0') return (Token){TOK_EOF, 0};
if (isdigit((unsigned char)c))
return (Token){TOK_NUM, lex_number()};
advance();
switch (c) {
case '+': return (Token){TOK_PLUS, 0};
case '-': return (Token){TOK_MINUS, 0};
case '*': return (Token){TOK_STAR, 0};
case '/': return (Token){TOK_SLASH, 0};
case '(': return (Token){TOK_LPAREN, 0};
case ')': return (Token){TOK_RPAREN, 0};
}
return (Token){TOK_EOF, 0};
}lexerを実行する
これは式をトークン化し、それぞれのトークンの種類を表示する完全なプログラムです。数値の場合は値も表示します。
TOK_EOF を読み取るとループが終了することに注目してください。
#include <stdio.h>
#include <ctype.h>
typedef enum { TOK_NUM, TOK_PLUS, TOK_STAR, TOK_EOF } TokKind;
typedef struct { TokKind kind; int value; } Token;
static const char *src;
static char peek(void){ return *src; }
static char advance(void){ return *src++; }
static Token next_token(void){
while (isspace((unsigned char)peek())) advance();
char c = peek();
if (c=='\0') return (Token){TOK_EOF,0};
if (isdigit((unsigned char)c)){
int n=0; while(isdigit((unsigned char)peek())) n=n*10+(advance()-'0');
return (Token){TOK_NUM,n};
}
advance();
if (c=='+') return (Token){TOK_PLUS,0};
return (Token){TOK_STAR,0};
}
int main(void){
src = "12 + 3 * 4";
Token t;
do {
t = next_token();
if (t.kind==TOK_NUM) printf("NUM %d\n", t.value);
else if (t.kind==TOK_PLUS) printf("PLUS\n");
else if (t.kind==TOK_STAR) printf("STAR\n");
else printf("EOF\n");
} while (t.kind != TOK_EOF);
return 0;
}1トークン先読み
パーサーでは通常、次のトークンを消費する前に調べる必要があります。グローバルな current に1つのトークンを格納し、マッチするたびに補充します。
この1トークン先読みで、今回のLL(1)文法には十分対応できます。
static Token current;
static void init_lexer(const char *s) {
src = s;
current = next_token();
}
static Token cur(void) { return current; }
static void bump(void) { current = next_token(); }字句エラーの報告
$ や @ などの未知の文字を、黙って消失させてはいけません。堅牢なlexerは問題のバイトを報告して中止します。
lexerで速やかに失敗させることで、後続の段階が壊れたトークンを受け取らずに済みます。
#include <stdio.h>
#include <stdlib.h>
static void lex_error(char c) {
fprintf(stderr, "lex error: unexpected '%c'\n", c);
exit(1);
}複数文字の演算子
実際の言語には == や <= のようなトークンがあります。これらを字句解析するには、最初の文字の後にもう1文字先読みします。
次のバイトで演算子が完成する場合は両方を消費し、そうでなければ1文字形式を生成します。
/* fragment: distinguish '=' from '==' */
if (peek() == '=') {
advance();
if (peek() == '=') { advance(); /* TOK_EQ */ }
else { /* TOK_ASSIGN */ }
}トークンが重要な理由
文字をトークンにまとめることで、パーサーは整理された型付きのストリームを扱えるようになります。演算子の優先順位、グループ化、エラーの処理についても考えやすくなります。
次は、これらのトークンを再帰下降パーサーに渡します。
クイックチェック
グループ化記号に対してlexerが何を生成するか考えてみましょう。
まとめ
lexerを構築しました。トークン型、スキャン用カーソル、空白のスキップ、数値の字句解析、そして1トークン先読みを行う next_token ディスパッチャです。
これらのトークンがパーサーへの入力となり、パーサーはそこから構文木を構築します。
よくある質問
「入力をトークン化する」レッスンは無料ですか?
はい。「入力をトークン化する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「入力をトークン化する」で何を学びますか?
テキストをトークンに変換します。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「入力をトークン化する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。