a21_txt01_2
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 川合のプログラミング言語自作のためのテキスト第三版#2
-(by [[K]], 2021.02.28)
** (1) HL-2
-HL-1では変数名も数値定数も1文字しか受け付けないという仕...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char *String; // こう書くと String は u...
void loadText(int argc, const char **argv, String t, int...
////////////////////////////////////////////////////////...
#define MAX_TC 1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当...
int tcs = 0, tcb = 0;
int var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) // トークン番号を得るための...
{
int i;
for (i = 0; i < tcs; i++) { // 登録済みの中から探す.
if (len == tl[i] && strncmp(s, ts[i], len) == 0)
break; // 見つかった!
}
if (i == tcs) {
if (tcs >= MAX_TC) {
printf("too many tokens\n");
exit(1);
}
strncpy(&tcBuf[tcb], s, len); // 見つからなかっ...
tcBuf[tcb + len] = 0; // 終端文字コード.
ts[i] = &tcBuf[tcb];
tl[i] = len;
tcb += len + 1;
tcs++;
var[i] = strtol(ts[i], 0, 0); // 定数だった場合...
}
return i;
}
////////////////////////////////////////////////////////...
int isAlphabetOrNumber(unsigned char c) // 変数名に使用...
{
if ('0' <= c && c <= '9') return 1;
if ('a' <= c && c <= 'z') return 1;
if ('A' <= c && c <= 'Z') return 1;
if (c == '_') return 1;
return 0;
}
int lexer(String s, int tc[]) // プログラムをトークンコ...
{
int i = 0, j = 0, len; // i:今s[]のどこを読んでいる...
for (;;) {
if (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' ...
i++;
continue;
}
if (s[i] == 0) // ファイル終端.
return j;
len = 0;
if (strchr("(){}[];,", s[i]) != 0) { // 1文字記号.
len = 1;
} else if (isAlphabetOrNumber(s[i])) { // 1文字...
while (isAlphabetOrNumber(s[i + len]))
len++;
} else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0...
while (strchr("=+-*/!%&~|<>?:.#", s[i + len]...
len++;
} else {
printf("syntax error : %.10s\n", &s[i]);
exit(1);
}
tc[j] = getTc(&s[i], len);
i += len;
j++;
}
}
int tc[10000]; // トークンコード.
////////////////////////////////////////////////////////...
int main(int argc, const char **argv)
{
int pc, pc1;
unsigned char txt[10000]; // ソースコード用のバッファ.
loadText(argc, argv, txt, 10000);
pc1 = lexer(txt, tc);
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
int semi = getTc(";", 1);
for (pc = 0; pc < pc1; pc++) { // プログラム実行開始.
if (tc[pc + 1] == getTc("=", 1) && tc[pc + 3] ==...
var[tc[pc]] = var[tc[pc + 2]];
} else if (tc[pc + 1] == getTc("=", 1) && tc[pc ...
var[tc[pc]] = var[tc[pc + 2]] + var[tc[pc + ...
} else if (tc[pc + 1] == getTc("=", 1) && tc[pc ...
var[tc[pc]] = var[tc[pc + 2]] - var[tc[pc + ...
} else if (tc[pc] == getTc("print", 5) && tc[pc ...
printf("%d\n", var[tc[pc + 1]]);
} else
goto err;
while (tc[pc] != semi)
pc++;
}
exit(0);
err:
printf("syntax error : %s %s %s %s\n", ts[tc[pc]], t...
exit(1);
}
-プログラムは128行になりました。このプログラムによって、...
abc = 123;
def = 456;
ans = abc + def;
ans = ans - 321;
print ans;
-この例では記号と英数字の間にスペースを入れていますが、そ...
** (2) HL-2の簡単な説明
-関数:
--void loadText(int argc, const char **argv, String t, in...
---コマンドライン引数で指定されたソースファイルをtに読み...
--int getTc(String s, int len)
---トークン(単語)をsに渡すと、それに対応するトークンコ...
--int isAlphabetOrNumber(unsigned char c)
---引数で渡された文字コードが、英数字であれば1を返す。そ...
---アンダースコアもHL-2の中ではアルファベットということに...
---この関数は以下のlexer()の下請け。
--int lexer(String s, int tc[])
---sにプログラムのソースコードを渡す。すると、tc[]にトー...
---より詳しい動作は、下記にあるように[[a21_txt01_2a]]を参...
--int main(int argc, const char **argv)
---言語処理の本体。
-変数:
--String ts[]
---getTc()が管理している配列変数で、トークンコードからト...
--int tl[]
---getTc()が管理している配列変数で、トークンコードからト...
--unsigned char tcBuf[]
---getTc()が管理している変数で、トークン文字列の実体を保...
--int tcs, tcb
---どちらもgetTc()が管理している変数で、tcsは今までに発行...
---tcbはtcBuf[]の未使用領域を指している。
---もしtcBuf[]やtcbの役割がピンとこない場合は、[[a21_txt0...
--int var[]
---変数の値を記憶しておくための変数。トークンコードをその...
--int tc[]
---プログラムをトークンコード列に変換したものがここに入る。
----
-変数名や定数が一文字で、余計なスペースが一切なかったHL-1...
-しかしHL-2以降では、変数名や定数の長さは自由になり、また...
-そこでまず、プログラムをトークンの集まりだと解釈して、ト...
-以下の比較を見れば、文字コードでの処理方法と、トークンコ...
HL-1での加算の処理:var[txt[pc]] = var[txt[pc + 2]] + va...
HL-2での加算の処理:var[tc [pc]] = var[tc [pc + 2]] + va...
-すごくよく似ていることが伝わるでしょうか・・・。
-とはいえ、文字コードとは異なり、どのトークン文字列が1番...
-ここまでの仕組みが分かれば、以下の説明はかなりわかりやす...
** (3) getTc()の説明
-今回はgetTc()とlexer()が主要な変更点なので、その二つを詳...
-まずはgetTc()から行きます。以下は上記プログラムの一部を...
#define MAX_TC 1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当...
int tcs = 0, tcb = 0;
int var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) // トークン番号を得るための...
{
int i;
for (i = 0; i < tcs; i++) { // 登録済みの中から探す.
if (len == tl[i] && strncmp(s, ts[i], len) == 0)
break; // 見つかった!
}
if (i == tcs) {
if (tcs >= MAX_TC) {
printf("too many tokens\n");
exit(1);
}
strncpy(&tcBuf[tcb], s, len); // 見つからなかっ...
tcBuf[tcb + len] = 0; // 終端文字コード.
ts[i] = &tcBuf[tcb];
tl[i] = len;
tcb += len + 1;
tcs++;
var[i] = strtol(ts[i], 0, 0); // 定数だった場合...
}
return i;
}
-まずgetTc()は、トークン文字列が始まる位置と、その文字数...
-なぜ単純にトークン文字列を渡す仕様ではなく、文字数を指定...
-getTc()では最初のループで、指定されたトークンが既に登録...
-見つからなかった場合、トークンを新規登録することになりま...
-この辺の処理が不慣れでよくわからない場合、[[a21_txt01_2b...
-最後に、変数に初期値を設定します。多くの場合、ここのstrt...
** (4) lexer()の説明
-次はlexer()です。・・・一般にソースプログラムをトークン...
-説明を分かりやすくするために、プログラムを再掲します。
int lexer(String s, int tc[]) // プログラムをトークンコ...
{
int i = 0, j = 0, len; // i:今s[]のどこを読んでいる...
for (;;) {
if (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' ...
i++;
continue;
}
if (s[i] == 0) // ファイル終端.
return j;
len = 0;
if (strchr("(){}[];,", s[i]) != 0) { // 1文字記号.
len = 1;
} else if (isAlphabetOrNumber(s[i])) { // 1文字...
while (isAlphabetOrNumber(s[i + len]))
len++;
} else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0...
while (strchr("=+-*/!%&~|<>?:.#", s[i + len]...
len++;
} else {
printf("syntax error : %.10s\n", &s[i]);
exit(1);
}
tc[j] = getTc(&s[i], len);
i += len;
j++;
}
}
-lexer()では、ソースコードを読みながら、以下の6通りの処理...
--[1]スペース、タブ、改行のコードを見つけた場合:
---特に何も出力することなく、読み飛ばします。
--[2]ソースコードの終端に達した場合:
---ここで変換処理を打ち切って、変換したトークン列の長さを...
--[3]かっこやセミコロン、コンマを見つけた場合:
---これらの記号は1文字で1トークンであるとして、len=1にし...
--[4]英数字を見つけた場合:
---これはおそらく変数名か定数です。ということで、英数字の...
--[5]=や+などの記号を見つけた場合:
---この種類の記号が続く限りlenを増やします。それでgetTc()...
---この方法だと、a=3;やa++;やa+=b;などはうまく切り分けら...
---しかし「a=-3;」と書いた場合、C言語なら「a」「=」「-」...
---でもまあ、たいていは「a = -3;」と書く人が多いと思うの...
-''lexer()がどんな結果を返しているのか、より詳しい説明ペ...
** (5) main()の説明
-main()はHL-1がわかっていれば難しいところはほとんどないと...
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
-ここが何をやっているのかよくわからないかもしれません。
-これはソースコードの末尾に、ピリオドのトークンを追加して...
-ではなぜこんなものが必要なのかというと、プログラムの末尾...
err:
printf("syntax error : %s %s %s %s\n", ts[tc[pc]], t...
exit(1);
-が実行されるわけですが、この時に、tc[pc + 1]やtc[pc + 2]...
-ということで全く本質的ではないですが、わからないと気にな...
** 次回に続く
-次回: [[a21_txt01_3]]
*こめんと欄
-最高!!説明が多くてわかりやすい。 -- ''Java大好き名無し...
#comment
終了行:
* 川合のプログラミング言語自作のためのテキスト第三版#2
-(by [[K]], 2021.02.28)
** (1) HL-2
-HL-1では変数名も数値定数も1文字しか受け付けないという仕...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char *String; // こう書くと String は u...
void loadText(int argc, const char **argv, String t, int...
////////////////////////////////////////////////////////...
#define MAX_TC 1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当...
int tcs = 0, tcb = 0;
int var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) // トークン番号を得るための...
{
int i;
for (i = 0; i < tcs; i++) { // 登録済みの中から探す.
if (len == tl[i] && strncmp(s, ts[i], len) == 0)
break; // 見つかった!
}
if (i == tcs) {
if (tcs >= MAX_TC) {
printf("too many tokens\n");
exit(1);
}
strncpy(&tcBuf[tcb], s, len); // 見つからなかっ...
tcBuf[tcb + len] = 0; // 終端文字コード.
ts[i] = &tcBuf[tcb];
tl[i] = len;
tcb += len + 1;
tcs++;
var[i] = strtol(ts[i], 0, 0); // 定数だった場合...
}
return i;
}
////////////////////////////////////////////////////////...
int isAlphabetOrNumber(unsigned char c) // 変数名に使用...
{
if ('0' <= c && c <= '9') return 1;
if ('a' <= c && c <= 'z') return 1;
if ('A' <= c && c <= 'Z') return 1;
if (c == '_') return 1;
return 0;
}
int lexer(String s, int tc[]) // プログラムをトークンコ...
{
int i = 0, j = 0, len; // i:今s[]のどこを読んでいる...
for (;;) {
if (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' ...
i++;
continue;
}
if (s[i] == 0) // ファイル終端.
return j;
len = 0;
if (strchr("(){}[];,", s[i]) != 0) { // 1文字記号.
len = 1;
} else if (isAlphabetOrNumber(s[i])) { // 1文字...
while (isAlphabetOrNumber(s[i + len]))
len++;
} else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0...
while (strchr("=+-*/!%&~|<>?:.#", s[i + len]...
len++;
} else {
printf("syntax error : %.10s\n", &s[i]);
exit(1);
}
tc[j] = getTc(&s[i], len);
i += len;
j++;
}
}
int tc[10000]; // トークンコード.
////////////////////////////////////////////////////////...
int main(int argc, const char **argv)
{
int pc, pc1;
unsigned char txt[10000]; // ソースコード用のバッファ.
loadText(argc, argv, txt, 10000);
pc1 = lexer(txt, tc);
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
int semi = getTc(";", 1);
for (pc = 0; pc < pc1; pc++) { // プログラム実行開始.
if (tc[pc + 1] == getTc("=", 1) && tc[pc + 3] ==...
var[tc[pc]] = var[tc[pc + 2]];
} else if (tc[pc + 1] == getTc("=", 1) && tc[pc ...
var[tc[pc]] = var[tc[pc + 2]] + var[tc[pc + ...
} else if (tc[pc + 1] == getTc("=", 1) && tc[pc ...
var[tc[pc]] = var[tc[pc + 2]] - var[tc[pc + ...
} else if (tc[pc] == getTc("print", 5) && tc[pc ...
printf("%d\n", var[tc[pc + 1]]);
} else
goto err;
while (tc[pc] != semi)
pc++;
}
exit(0);
err:
printf("syntax error : %s %s %s %s\n", ts[tc[pc]], t...
exit(1);
}
-プログラムは128行になりました。このプログラムによって、...
abc = 123;
def = 456;
ans = abc + def;
ans = ans - 321;
print ans;
-この例では記号と英数字の間にスペースを入れていますが、そ...
** (2) HL-2の簡単な説明
-関数:
--void loadText(int argc, const char **argv, String t, in...
---コマンドライン引数で指定されたソースファイルをtに読み...
--int getTc(String s, int len)
---トークン(単語)をsに渡すと、それに対応するトークンコ...
--int isAlphabetOrNumber(unsigned char c)
---引数で渡された文字コードが、英数字であれば1を返す。そ...
---アンダースコアもHL-2の中ではアルファベットということに...
---この関数は以下のlexer()の下請け。
--int lexer(String s, int tc[])
---sにプログラムのソースコードを渡す。すると、tc[]にトー...
---より詳しい動作は、下記にあるように[[a21_txt01_2a]]を参...
--int main(int argc, const char **argv)
---言語処理の本体。
-変数:
--String ts[]
---getTc()が管理している配列変数で、トークンコードからト...
--int tl[]
---getTc()が管理している配列変数で、トークンコードからト...
--unsigned char tcBuf[]
---getTc()が管理している変数で、トークン文字列の実体を保...
--int tcs, tcb
---どちらもgetTc()が管理している変数で、tcsは今までに発行...
---tcbはtcBuf[]の未使用領域を指している。
---もしtcBuf[]やtcbの役割がピンとこない場合は、[[a21_txt0...
--int var[]
---変数の値を記憶しておくための変数。トークンコードをその...
--int tc[]
---プログラムをトークンコード列に変換したものがここに入る。
----
-変数名や定数が一文字で、余計なスペースが一切なかったHL-1...
-しかしHL-2以降では、変数名や定数の長さは自由になり、また...
-そこでまず、プログラムをトークンの集まりだと解釈して、ト...
-以下の比較を見れば、文字コードでの処理方法と、トークンコ...
HL-1での加算の処理:var[txt[pc]] = var[txt[pc + 2]] + va...
HL-2での加算の処理:var[tc [pc]] = var[tc [pc + 2]] + va...
-すごくよく似ていることが伝わるでしょうか・・・。
-とはいえ、文字コードとは異なり、どのトークン文字列が1番...
-ここまでの仕組みが分かれば、以下の説明はかなりわかりやす...
** (3) getTc()の説明
-今回はgetTc()とlexer()が主要な変更点なので、その二つを詳...
-まずはgetTc()から行きます。以下は上記プログラムの一部を...
#define MAX_TC 1000 // トークンコードの最大値.
String ts[MAX_TC + 1]; // トークンの内容(文字列)を記憶.
int tl[MAX_TC + 1]; // トークンの長さ.
unsigned char tcBuf[(MAX_TC + 1) * 10]; // トークン1つ当...
int tcs = 0, tcb = 0;
int var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) // トークン番号を得るための...
{
int i;
for (i = 0; i < tcs; i++) { // 登録済みの中から探す.
if (len == tl[i] && strncmp(s, ts[i], len) == 0)
break; // 見つかった!
}
if (i == tcs) {
if (tcs >= MAX_TC) {
printf("too many tokens\n");
exit(1);
}
strncpy(&tcBuf[tcb], s, len); // 見つからなかっ...
tcBuf[tcb + len] = 0; // 終端文字コード.
ts[i] = &tcBuf[tcb];
tl[i] = len;
tcb += len + 1;
tcs++;
var[i] = strtol(ts[i], 0, 0); // 定数だった場合...
}
return i;
}
-まずgetTc()は、トークン文字列が始まる位置と、その文字数...
-なぜ単純にトークン文字列を渡す仕様ではなく、文字数を指定...
-getTc()では最初のループで、指定されたトークンが既に登録...
-見つからなかった場合、トークンを新規登録することになりま...
-この辺の処理が不慣れでよくわからない場合、[[a21_txt01_2b...
-最後に、変数に初期値を設定します。多くの場合、ここのstrt...
** (4) lexer()の説明
-次はlexer()です。・・・一般にソースプログラムをトークン...
-説明を分かりやすくするために、プログラムを再掲します。
int lexer(String s, int tc[]) // プログラムをトークンコ...
{
int i = 0, j = 0, len; // i:今s[]のどこを読んでいる...
for (;;) {
if (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' ...
i++;
continue;
}
if (s[i] == 0) // ファイル終端.
return j;
len = 0;
if (strchr("(){}[];,", s[i]) != 0) { // 1文字記号.
len = 1;
} else if (isAlphabetOrNumber(s[i])) { // 1文字...
while (isAlphabetOrNumber(s[i + len]))
len++;
} else if (strchr("=+-*/!%&~|<>?:.#", s[i]) != 0...
while (strchr("=+-*/!%&~|<>?:.#", s[i + len]...
len++;
} else {
printf("syntax error : %.10s\n", &s[i]);
exit(1);
}
tc[j] = getTc(&s[i], len);
i += len;
j++;
}
}
-lexer()では、ソースコードを読みながら、以下の6通りの処理...
--[1]スペース、タブ、改行のコードを見つけた場合:
---特に何も出力することなく、読み飛ばします。
--[2]ソースコードの終端に達した場合:
---ここで変換処理を打ち切って、変換したトークン列の長さを...
--[3]かっこやセミコロン、コンマを見つけた場合:
---これらの記号は1文字で1トークンであるとして、len=1にし...
--[4]英数字を見つけた場合:
---これはおそらく変数名か定数です。ということで、英数字の...
--[5]=や+などの記号を見つけた場合:
---この種類の記号が続く限りlenを増やします。それでgetTc()...
---この方法だと、a=3;やa++;やa+=b;などはうまく切り分けら...
---しかし「a=-3;」と書いた場合、C言語なら「a」「=」「-」...
---でもまあ、たいていは「a = -3;」と書く人が多いと思うの...
-''lexer()がどんな結果を返しているのか、より詳しい説明ペ...
** (5) main()の説明
-main()はHL-1がわかっていれば難しいところはほとんどないと...
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
-ここが何をやっているのかよくわからないかもしれません。
-これはソースコードの末尾に、ピリオドのトークンを追加して...
-ではなぜこんなものが必要なのかというと、プログラムの末尾...
err:
printf("syntax error : %s %s %s %s\n", ts[tc[pc]], t...
exit(1);
-が実行されるわけですが、この時に、tc[pc + 1]やtc[pc + 2]...
-ということで全く本質的ではないですが、わからないと気にな...
** 次回に続く
-次回: [[a21_txt01_3]]
*こめんと欄
-最高!!説明が多くてわかりやすい。 -- ''Java大好き名無し...
#comment
ページ名: