- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
Forthで文字列を表示するには、「."」を用いる。
." Hello, World."
最後の「"」で、表示する文字の最後を表す。文字列と"の間には空白は必要ない。
ところで、Forthの内部では、文字列は文字数と文字列本体で表現されるらしい。
C言語のように0終端ではないのだ。
そうすると、."の構文解析というのは、
."コード, 文字数, 文字列本体
となるように仮想マシンコードを作らなければならない。
それはまあ良いのだが、どうやって文字列を得るか、頭を悩ませている。
構文解析する際、トークンごとに文字列を得ているのだが、それだと文字列中の空白をすべて無視してしまう。
困った。
どうすればよいだろうか。以下の様に変更することにする。
* トークンの取り出しにstrtok()を使うのをやめる
* ."が現れたら、トークン単位の読み込みをやめ、"が現れるまで1文字ずつ読み進む
まず、バッファを次の構造体にする。
/**
* ソースコード入力バッファ
*/
typedef struct srccode_buffer {
char *buf; /**< バッファ */
int pos; /**< 取り出し位置 */
} SRC_BUFFER;
バッファを宣言する。
int main(int argc, char *argv[])
{
char buf[100];
SRC_BUFFER cmd_buf = {buf, 0};
init();
if (argc >= 2) {
load_prog(argv[1], &cmd_buf);
parse(&cmd_buf);
proc_prog();
} else {
while (!quit_enabled) {
printf(">");
scanf("%100[^\n]%*[^\n]", cmd_buf.buf);
getchar();
parse(&cmd_buf);
if (!proc_disable_cnt) {
proc_prog();
}
}
}
return 0;
}
load_prog()を修正する。
/**
* Forthで書かれたプログラムをロードする
*/
void load_prog(char *fname, SRC_BUFFER *cmd)
{
FILE *fp;
unsigned int idx = 0;
char c;
fp = fopen(fname, "r");
while ((c = fgetc(fp)) != EOF) {
cmd->buf[idx++] = c;
}
cmd->buf[idx] = '\x0';
cmd->pos = 0;
fclose(fp);
}
parse()を内で使われているstrtok()をget_token()に置き換える。
token = get_token(cmd);
get_token()を作成する。
/**
* バッファからトークンを切り出す
*/
char *get_token(SRC_BUFFER *bufptr)
{
char *token_ptr;
if (bufptr != NULL) {
srcbuf = bufptr;
srcbuf->pos = 0;
}
/* 最初が区切り子なら、無視する */
while (is_separator(srcbuf->buf[srcbuf->pos])) {
srcbuf->pos++;
}
/* 先頭位置を得る */
token_ptr = &srcbuf->buf[srcbuf->pos];
/* 区切り子を探す */
while (!is_separator(srcbuf->buf[srcbuf->pos]) && srcbuf->buf[srcbuf->pos] != '\x0') {
srcbuf->pos++;
}
/* 終端する */
srcbuf->buf[srcbuf->pos] = '\x0';
srcbuf->pos++;
return token_ptr;
}
get_toquote()を作成する。
/**
* バッファから'"'終端している文字列を返す
*/
char *get_toquote(SRC_BUFFER *bufptr)
{
char *token_ptr;
if (bufptr != NULL) {
srcbuf = bufptr;
srcbuf->pos = 0;
}
/* 最初が区切り子なら、無視する */
while (is_separator(srcbuf->buf[srcbuf->pos])) {
srcbuf->pos++;
}
/* 先頭位置を得る */
token_ptr = &srcbuf->buf[srcbuf->pos];
/* '"'を探す */
while (srcbuf->buf[srcbuf->pos] != '"' && srcbuf->buf[srcbuf->pos] != '\x0') {
srcbuf->pos++;
}
/* 終端する */
srcbuf->buf[srcbuf->pos] = '\x0';
srcbuf->pos++;
return token_ptr;
}
parse()に."時の処理を追加する。
} else if (strcmp(token, ".\"") == 0) {
int j;
prog[parse_idx++] = CODE_DOTQUOTE;
token = get_toquote(NULL);
*(unsigned short *)(prog + parse_idx) = strlen(token);
parse_idx += 2;
for (j = 0; token[j] != '\x0'; j++) {
prog[parse_idx++] = token[j]
}
}
実際の処理を行う関数call_dotquote()を追加。
/**
* ."処理を行う
*/
void call_dotquote(void)
{
unsigned short j;
unsigned short len = *(unsigned short *)(prog + prog_cnt);
prog_cnt += 2;
for (j = 0; j <len ; j++) {
printf("%c", prog[prog_cnt++]);
}
}
テストファイルtestfile/test8の内容
." ABCD abcd"
実行してみた。
$ ./moiforth.exe testfile/test8
ABCD abcd
成功した。
[ソースコード|http://www.moi2.sakura.ne.jp/fswiki/wiki.cgi?page=Forth%A4%F2%BA%EE%A4%C3%A4%C6%A4%DF%A4%EB+%2F+%CA%B8%BB%FA%CE%F3%A4%F2%C9%BD%BC%A8%A4%B9%A4%EB&file=moiforth%2D0%2E9%2Ezip&action=ATTACH]
(2009.09.16)
[[戻る|Forthを作ってみる]] [[前へ|Forthを作ってみる / スレッディングの変更]] [[次へ|Forthを作ってみる / 文字列を表示する]]
[[戻る|Forthを作ってみる]] [[前へ|Forthを作ってみる / スレッディングの変更]] [[次へ|Forthを作ってみる / 変数を実装する]]
{{adsence}}