a21_txt02_1a
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 「10日くらいでできる!プログラミング言語自作入門」の続...
-(by [[K]], 2021.04.09)
** (1) HL-11a
-HL-11では、JITコンパイラ化のための下準備がメインで、命令...
-さすがにそれだけではさみしすぎるので、普通の演算子を全部...
-改造の方針としては、いくつかのputIc()をputIcX86()に書き...
#include <acl.c>
typedef unsigned char *String; // こう書くと String は u...
int loadText(String path, String t, int siz) → HL-4と同...
////////////////////////////////////////////////////////...
#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;
AInt var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) → HL-8aと同じなので省略
////////////////////////////////////////////////////////...
int isAlphabetOrNumber(unsigned char c) → HL-2と同じなの...
int lexer(String s, int tc[]) → HL-9aと同じなので省略
int tc[10000]; // トークンコード.
enum { TcSemi = 0, TcDot, TcWiCard, Tc0, Tc1, Tc2, Tc3, ...
TcEEq, TcNEq, TcLt, TcGe, TcLe, TcGt, TcPlus, TcMinu...
TcComma, TcExpr, TcExpr0, TcTmp0, TcTmp1, TcTmp2, Tc...
char tcInit[] = "; . !!* 0 1 2 3 4 5 6 7 8 ( ) [ ] { } =...
////////////////////////////////////////////////////////...
int phrCmp_tc[32 * 100], ppc1, wpc[9], wpc1[9]; // ppc1:...
int phrCmp(int pid, String phr, int pc) → HL-7と同じなの...
////////////////////////////////////////////////////////...
typedef AInt *IntP; // こう書くと IntP は AInt * の代わ...
enum { OpCpy = 0, OpCeq, OpCne, OpClt, OpCge, OpCle, OpC...
OpAdd1, OpNeg, OpGoto, OpJeq, OpJne, OpJlt, OpJge, O...
OpPrints, OpAryNew, OpAryInit, OpArySet, OpAryGet, O...
OpXorShift, OpGetPix, OpFilRct0, OpPrm, OpF16Sin, Op...
String opBin[] = { // 二項演算子のための機械語.
"8b_%1m0; 3b_%2m0; 0f_94_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_95_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9c_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9d_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9e_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9f_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 03_%2m0; 89_%0m0;", /...
"8b_%1m0; 2b_%2m0; 89_%0m0;", /...
"8b_%1m0; 0f_af_%2m0; 89_%0m0;", /...
"8b_%1m0; 99; f7_%2m7; 89_%0m0;", /...
"8b_%1m0; 99; f7_%2m7; 89_%0m2;", /...
"8b_%1m0; 23_%2m0; 89_%0m0;", /...
"8b_%1m0; 8b_%2m1; d3_f8; 89_%0m0;" /...
};
unsigned char *ic, *icq; // ic[]:内部コード、icq:ic[]へ...
void putIc(int op, IntP p0, IntP p1, IntP p2, IntP p3) →...
int getHex(int c) → HL-11と同じなので省略
int get32(unsigned char *p) → HL-11と同じなので省略
void put32(unsigned char *p, int i) → HL-11と同じなので...
void putIcX86_sub(String s, IntP a[]) → HL-11と同じなの...
void putIcX86(String s, IntP p0, IntP p1, IntP p2, IntP ...
////////////////////////////////////////////////////////...
char tmp_flag[10]; // 一時変数の利用状況を管理.
int tmpAlloc() → HL-7と同じなので省略
void tmpFree(int i) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
void sub_print(int i) → HL-11と同じなので省略
////////////////////////////////////////////////////////...
int epc, epc1; // exprのためのpcとpc1.
int exprSub(int priority); // exprSub1()が参照するので、...
int expr(int j);
int phrCmpPutIc(int pid, String phr, int pc, int *pi, in...
int phrCmpPutIcX86(int pid, String phr, int pc, int *pi,...
int exprSub1(int i, int priority, int op) // 二項演算子...
{
int j, k;
epc++;
j = exprSub(priority);
k = tmpAlloc();
! putIcX86(opBin[op - TcEEq], &var[k], &var[i], &var[j...
tmpFree(i);
tmpFree(j);
if (i < 0 || j < 0) return -1;
return k;
}
int exprSub(int priority)
{
int i = -1, e0 = 0, e1 = 0;
ppc1 = 0;
if (phrCmp(99, "( !!**0 )", epc)) { // かっこ.
i = expr(0);
} else if (tc[epc] == TcPlPlus) { // 前置インクリメ...
epc++;
i = exprSub(2);
! putIcX86("8b_%0m0; 40; 89_%0m0;", &var[i], 0, 0,...
} else if (tc[epc] == TcMinus) { // 単項マイナス.
epc++;
e0 = exprSub(2);
i = tmpAlloc();
! putIcX86("8b_%1m0; f7_d8; 89_%0m0;", &var[i], &v...
} else if (phrCmpPutIc(72, "mul64shr(!!**1, !!**2, !...
} else if (phrCmpPutIc(73, "aRgb8(!!**1, !!**2, !!**...
} else if (phrCmpPutIc(74, "aOpenWin(!!**0, !!**1, !...
i = Tc0;
} else if (phrCmpPutIc(75, "aXorShift32()", ...
} else if (phrCmpPutIc(76, "aGetPix(!!**8, !!**1, !!...
} else if (phrCmpPutIc(77, "ff16sin(!!**1)", ...
} else if (phrCmpPutIc(78, "ff16cos(!!**1)", ...
} else if (phrCmpPutIc(79, "aInkey(!!***8 , !!**1)",...
} else { // 変数もしくは定数.
i = tc[epc];
epc++;
}
if (ppc1 > 0)
epc = ppc1;
for (;;) {
tmpFree(e0);
tmpFree(e1);
if (i < 0 || e0 < 0 || e1 < 0) return -1; // こ...
if (epc >= epc1) break;
e0 = e1 = 0;
if (tc[epc] == TcPlPlus) { // 後置インクリメント.
epc++;
e0 = i;
i = tmpAlloc();
! putIcX86("8b_%1m0; 89_%0m0; 40; 89_%1m0;", &...
} else if (phrCmp(70, "[!!**0]=", epc) && priori...
e1 = i;
e0 = expr(0);
epc = ppc1;
i = exprSub(15);
putIc(OpArySet, &var[e1], &var[e0], &var[i],...
} else if (phrCmp(71, "[!!**0]", epc)) {
e1 = i;
i = tmpAlloc();
e0 = expr(0);
putIc(OpAryGet, &var[e1], &var[e0], &var[i],...
epc = ppc1;
} else if (TcAster <= tc[epc] && tc[epc] <= TcPe...
! i = exprSub1(i, 3, tc[epc]); // 左結合なので...
} else if (TcPlus <= tc[epc] && tc[epc] <= TcMi...
! i = exprSub1(i, 4, tc[epc]); // 左結合なので...
} else if (tc[epc] == TcShr && priority >= 6) {
! i = exprSub1(i, 5, TcShr); // 左結合なので6...
} else if (TcLt <= tc[epc] && tc[epc] <= TcGt...
! i = exprSub1(i, 6, tc[epc]); // 左結合なので...
} else if (TcEEq <= tc[epc] && tc[epc] <= TcNE...
! i = exprSub1(i, 7, tc[epc]); // 左結合なので...
} else if (tc[epc] == TcAnd && priority >= 9) {
! i = exprSub1(i, 8, TcAnd); // 左結合なので9...
} else if (tc[epc] == TcEqu && priority >= 15) {
epc++;
e0 = exprSub(15); // 右結合なので15のまま.
! putIcX86("8b_%1m0; 89_%0m0;", &var[i], &var[...
} else
break;
}
return i;
}
int expr(int j) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
(中略)
////////////////////////////////////////////////////////...
int compile(String s)
{
int pc, pc1, i, j;
unsigned char *icq1, *icp;
pc1 = lexer(s, tc);
tc[pc1++] = TcSemi; // 末尾に「;」を付け忘れることが...
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
icq = ic;
putIcX86("60; 83_ec_7c;", 0, 0, 0, 0); // PUSHAD(); ...
for (i = 0; i < 10; i++) {
tmp_flag[i] = 0;
}
tmpLabelNo = 0;
bd = lbd = 0;
for (pc = 0; pc < pc1; ) { // コンパイル開始.
int e0 = 0, e2 = 0;
if (phrCmp( 1, "!!*0 = !!*1;", pc)) { // 単純代入.
putIcX86("8b_%1m0; 89_%0m0;", &var[tc[wpc[0]...
} else if (phrCmp(10, "!!*0 = !!*1 + 1; if (!!*2...
putIc(OpLop, &var[tc[wpc[4]]], &var[tc[wpc[0...
} else if (phrCmp( 9, "!!*0 = !!*1 + 1;", pc) &&...
! putIcX86("8b_%0m0; 40; 89_%0m0;", &var[tc[wp...
} else if (phrCmp( 2, "!!*0 = !!*1 !!*2 !!*3;", ...
! putIcX86(opBin[tc[wpc[2]] - TcEEq], &var[tc[...
} else if (phrCmpPutIcX86(4, "print !!**0;", pc,...
(中略)
}
int run(String s) → HL-11と同じなので省略
// 以下のmallocRWX()はWindows用の記述.
#include <windows.h>
void *mallocRWX(int siz) → HL-11と同じなので省略
////////////////////////////////////////////////////////...
void aMain() → HL-11と同じなので省略
-プログラムは707行になりました。そして基本的な計算機能は...
>print (1+2)*3
9
-もちろん他にも変数を使った演算なども自由にできますが、例...
** (2) 機械語の説明
-8bや89については、もうすでに説明したので、ここでは説明を...
-表の中の%mは、mod r/mバイトを表しています。
|3b_%m|比較命令。大小を比べる際には、まずこの命令を使って...
|0f_94_c0 ~ 0f_9f_c0|比較結果に応じて、EAXレジスタの下位...
|0f_b6_c0|EAXの上位24bitを0クリアする。|アセンブラではMOV...
|03_%m|加算命令。|アセンブラではADD命令|
|2b_%m|減算命令。|アセンブラではSUB命令|
|0f_af_%m|符号付き乗算命令。|アセンブラではIMUL命令|
|99|EAXをEDX:EAXに符号拡張する(IDIVの直前によく用いられ...
|f7_%m/7|符号付き除算・剰余演算命令。商はEAX、剰余がEDXに...
|23_%m|AND計算(ビット演算)。|アセンブラではAND命令|
|d3_f8|EAX = EAX >> ECX; を計算。|アセンブラではSAR命令|
|40|EAX++; を計算。|アセンブラではINC命令|
|f7_d8|EAX = - EAX; を計算。|アセンブラではNEG命令|
--除算命令のところの「/7」の意味は、mod r/mバイトの中の第...
--除算命令は、割られる数は EDX:EAX で固定なので、mod r/m ...
--参考までに、命令f7の/0~/7を全部書いておきます。
|f7_%m/0|f7_%m/1|f7_%m/2|f7_%m/3|f7_%m/4|f7_%m/5|f7_%m/6|...
|TEST|使用しない|NOT|NEG|MUL|IMUL|DIV|IDIV|
--類似のテクニックは命令83や命令d3でも見られます。
** 次回に続く
-次回: [[a21_txt02_2]]
*こめんと欄
#comment
終了行:
* 「10日くらいでできる!プログラミング言語自作入門」の続...
-(by [[K]], 2021.04.09)
** (1) HL-11a
-HL-11では、JITコンパイラ化のための下準備がメインで、命令...
-さすがにそれだけではさみしすぎるので、普通の演算子を全部...
-改造の方針としては、いくつかのputIc()をputIcX86()に書き...
#include <acl.c>
typedef unsigned char *String; // こう書くと String は u...
int loadText(String path, String t, int siz) → HL-4と同...
////////////////////////////////////////////////////////...
#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;
AInt var[MAX_TC + 1]; // 変数.
int getTc(String s, int len) → HL-8aと同じなので省略
////////////////////////////////////////////////////////...
int isAlphabetOrNumber(unsigned char c) → HL-2と同じなの...
int lexer(String s, int tc[]) → HL-9aと同じなので省略
int tc[10000]; // トークンコード.
enum { TcSemi = 0, TcDot, TcWiCard, Tc0, Tc1, Tc2, Tc3, ...
TcEEq, TcNEq, TcLt, TcGe, TcLe, TcGt, TcPlus, TcMinu...
TcComma, TcExpr, TcExpr0, TcTmp0, TcTmp1, TcTmp2, Tc...
char tcInit[] = "; . !!* 0 1 2 3 4 5 6 7 8 ( ) [ ] { } =...
////////////////////////////////////////////////////////...
int phrCmp_tc[32 * 100], ppc1, wpc[9], wpc1[9]; // ppc1:...
int phrCmp(int pid, String phr, int pc) → HL-7と同じなの...
////////////////////////////////////////////////////////...
typedef AInt *IntP; // こう書くと IntP は AInt * の代わ...
enum { OpCpy = 0, OpCeq, OpCne, OpClt, OpCge, OpCle, OpC...
OpAdd1, OpNeg, OpGoto, OpJeq, OpJne, OpJlt, OpJge, O...
OpPrints, OpAryNew, OpAryInit, OpArySet, OpAryGet, O...
OpXorShift, OpGetPix, OpFilRct0, OpPrm, OpF16Sin, Op...
String opBin[] = { // 二項演算子のための機械語.
"8b_%1m0; 3b_%2m0; 0f_94_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_95_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9c_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9d_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9e_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 3b_%2m0; 0f_9f_c0; 0f_b6_c0; 89_%0m0;", /...
"8b_%1m0; 03_%2m0; 89_%0m0;", /...
"8b_%1m0; 2b_%2m0; 89_%0m0;", /...
"8b_%1m0; 0f_af_%2m0; 89_%0m0;", /...
"8b_%1m0; 99; f7_%2m7; 89_%0m0;", /...
"8b_%1m0; 99; f7_%2m7; 89_%0m2;", /...
"8b_%1m0; 23_%2m0; 89_%0m0;", /...
"8b_%1m0; 8b_%2m1; d3_f8; 89_%0m0;" /...
};
unsigned char *ic, *icq; // ic[]:内部コード、icq:ic[]へ...
void putIc(int op, IntP p0, IntP p1, IntP p2, IntP p3) →...
int getHex(int c) → HL-11と同じなので省略
int get32(unsigned char *p) → HL-11と同じなので省略
void put32(unsigned char *p, int i) → HL-11と同じなので...
void putIcX86_sub(String s, IntP a[]) → HL-11と同じなの...
void putIcX86(String s, IntP p0, IntP p1, IntP p2, IntP ...
////////////////////////////////////////////////////////...
char tmp_flag[10]; // 一時変数の利用状況を管理.
int tmpAlloc() → HL-7と同じなので省略
void tmpFree(int i) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
void sub_print(int i) → HL-11と同じなので省略
////////////////////////////////////////////////////////...
int epc, epc1; // exprのためのpcとpc1.
int exprSub(int priority); // exprSub1()が参照するので、...
int expr(int j);
int phrCmpPutIc(int pid, String phr, int pc, int *pi, in...
int phrCmpPutIcX86(int pid, String phr, int pc, int *pi,...
int exprSub1(int i, int priority, int op) // 二項演算子...
{
int j, k;
epc++;
j = exprSub(priority);
k = tmpAlloc();
! putIcX86(opBin[op - TcEEq], &var[k], &var[i], &var[j...
tmpFree(i);
tmpFree(j);
if (i < 0 || j < 0) return -1;
return k;
}
int exprSub(int priority)
{
int i = -1, e0 = 0, e1 = 0;
ppc1 = 0;
if (phrCmp(99, "( !!**0 )", epc)) { // かっこ.
i = expr(0);
} else if (tc[epc] == TcPlPlus) { // 前置インクリメ...
epc++;
i = exprSub(2);
! putIcX86("8b_%0m0; 40; 89_%0m0;", &var[i], 0, 0,...
} else if (tc[epc] == TcMinus) { // 単項マイナス.
epc++;
e0 = exprSub(2);
i = tmpAlloc();
! putIcX86("8b_%1m0; f7_d8; 89_%0m0;", &var[i], &v...
} else if (phrCmpPutIc(72, "mul64shr(!!**1, !!**2, !...
} else if (phrCmpPutIc(73, "aRgb8(!!**1, !!**2, !!**...
} else if (phrCmpPutIc(74, "aOpenWin(!!**0, !!**1, !...
i = Tc0;
} else if (phrCmpPutIc(75, "aXorShift32()", ...
} else if (phrCmpPutIc(76, "aGetPix(!!**8, !!**1, !!...
} else if (phrCmpPutIc(77, "ff16sin(!!**1)", ...
} else if (phrCmpPutIc(78, "ff16cos(!!**1)", ...
} else if (phrCmpPutIc(79, "aInkey(!!***8 , !!**1)",...
} else { // 変数もしくは定数.
i = tc[epc];
epc++;
}
if (ppc1 > 0)
epc = ppc1;
for (;;) {
tmpFree(e0);
tmpFree(e1);
if (i < 0 || e0 < 0 || e1 < 0) return -1; // こ...
if (epc >= epc1) break;
e0 = e1 = 0;
if (tc[epc] == TcPlPlus) { // 後置インクリメント.
epc++;
e0 = i;
i = tmpAlloc();
! putIcX86("8b_%1m0; 89_%0m0; 40; 89_%1m0;", &...
} else if (phrCmp(70, "[!!**0]=", epc) && priori...
e1 = i;
e0 = expr(0);
epc = ppc1;
i = exprSub(15);
putIc(OpArySet, &var[e1], &var[e0], &var[i],...
} else if (phrCmp(71, "[!!**0]", epc)) {
e1 = i;
i = tmpAlloc();
e0 = expr(0);
putIc(OpAryGet, &var[e1], &var[e0], &var[i],...
epc = ppc1;
} else if (TcAster <= tc[epc] && tc[epc] <= TcPe...
! i = exprSub1(i, 3, tc[epc]); // 左結合なので...
} else if (TcPlus <= tc[epc] && tc[epc] <= TcMi...
! i = exprSub1(i, 4, tc[epc]); // 左結合なので...
} else if (tc[epc] == TcShr && priority >= 6) {
! i = exprSub1(i, 5, TcShr); // 左結合なので6...
} else if (TcLt <= tc[epc] && tc[epc] <= TcGt...
! i = exprSub1(i, 6, tc[epc]); // 左結合なので...
} else if (TcEEq <= tc[epc] && tc[epc] <= TcNE...
! i = exprSub1(i, 7, tc[epc]); // 左結合なので...
} else if (tc[epc] == TcAnd && priority >= 9) {
! i = exprSub1(i, 8, TcAnd); // 左結合なので9...
} else if (tc[epc] == TcEqu && priority >= 15) {
epc++;
e0 = exprSub(15); // 右結合なので15のまま.
! putIcX86("8b_%1m0; 89_%0m0;", &var[i], &var[...
} else
break;
}
return i;
}
int expr(int j) → HL-7と同じなので省略
////////////////////////////////////////////////////////...
(中略)
////////////////////////////////////////////////////////...
int compile(String s)
{
int pc, pc1, i, j;
unsigned char *icq1, *icp;
pc1 = lexer(s, tc);
tc[pc1++] = TcSemi; // 末尾に「;」を付け忘れることが...
tc[pc1] = tc[pc1 + 1] = tc[pc1 + 2] = tc[pc1 + 3] = ...
icq = ic;
putIcX86("60; 83_ec_7c;", 0, 0, 0, 0); // PUSHAD(); ...
for (i = 0; i < 10; i++) {
tmp_flag[i] = 0;
}
tmpLabelNo = 0;
bd = lbd = 0;
for (pc = 0; pc < pc1; ) { // コンパイル開始.
int e0 = 0, e2 = 0;
if (phrCmp( 1, "!!*0 = !!*1;", pc)) { // 単純代入.
putIcX86("8b_%1m0; 89_%0m0;", &var[tc[wpc[0]...
} else if (phrCmp(10, "!!*0 = !!*1 + 1; if (!!*2...
putIc(OpLop, &var[tc[wpc[4]]], &var[tc[wpc[0...
} else if (phrCmp( 9, "!!*0 = !!*1 + 1;", pc) &&...
! putIcX86("8b_%0m0; 40; 89_%0m0;", &var[tc[wp...
} else if (phrCmp( 2, "!!*0 = !!*1 !!*2 !!*3;", ...
! putIcX86(opBin[tc[wpc[2]] - TcEEq], &var[tc[...
} else if (phrCmpPutIcX86(4, "print !!**0;", pc,...
(中略)
}
int run(String s) → HL-11と同じなので省略
// 以下のmallocRWX()はWindows用の記述.
#include <windows.h>
void *mallocRWX(int siz) → HL-11と同じなので省略
////////////////////////////////////////////////////////...
void aMain() → HL-11と同じなので省略
-プログラムは707行になりました。そして基本的な計算機能は...
>print (1+2)*3
9
-もちろん他にも変数を使った演算なども自由にできますが、例...
** (2) 機械語の説明
-8bや89については、もうすでに説明したので、ここでは説明を...
-表の中の%mは、mod r/mバイトを表しています。
|3b_%m|比較命令。大小を比べる際には、まずこの命令を使って...
|0f_94_c0 ~ 0f_9f_c0|比較結果に応じて、EAXレジスタの下位...
|0f_b6_c0|EAXの上位24bitを0クリアする。|アセンブラではMOV...
|03_%m|加算命令。|アセンブラではADD命令|
|2b_%m|減算命令。|アセンブラではSUB命令|
|0f_af_%m|符号付き乗算命令。|アセンブラではIMUL命令|
|99|EAXをEDX:EAXに符号拡張する(IDIVの直前によく用いられ...
|f7_%m/7|符号付き除算・剰余演算命令。商はEAX、剰余がEDXに...
|23_%m|AND計算(ビット演算)。|アセンブラではAND命令|
|d3_f8|EAX = EAX >> ECX; を計算。|アセンブラではSAR命令|
|40|EAX++; を計算。|アセンブラではINC命令|
|f7_d8|EAX = - EAX; を計算。|アセンブラではNEG命令|
--除算命令のところの「/7」の意味は、mod r/mバイトの中の第...
--除算命令は、割られる数は EDX:EAX で固定なので、mod r/m ...
--参考までに、命令f7の/0~/7を全部書いておきます。
|f7_%m/0|f7_%m/1|f7_%m/2|f7_%m/3|f7_%m/4|f7_%m/5|f7_%m/6|...
|TEST|使用しない|NOT|NEG|MUL|IMUL|DIV|IDIV|
--類似のテクニックは命令83や命令d3でも見られます。
** 次回に続く
-次回: [[a21_txt02_2]]
*こめんと欄
#comment
ページ名: