0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

forthAdvent Calendar 2024

Day 15

ChatGPT先生にforthを教えてもらう

Posted at

はじめに

この記事は、forth Advent Calendar 2024 の15日目の記事となります。

アドベントカレンダのリストを見ていて、今、forthに初めて来た者の記録です。

基本事項

forthってなに? というわけでChatGPT先生に聞いてみる。

スクリーンショット 2024-12-20 10.37.16.png
スクリーンショット 2024-12-20 10.37.24.png

実行したい

スクリーンショット 2024-12-20 10.39.33.png

スクリーンショット 2024-12-20 10.40.14.png

おお。これはお手軽に試せる。

1
: SQUARE ( n -- n^2 ) DUP * ;
5 SQUARE .

スクリーンショット 2024-12-20 10.43.26.png

https://tio.run/#forth-gforth
で実行してみよう。

https://tio.run/##S8svKsnQTU8DUf//WykEB4Y6BrkqaCjkKejqKuTFGSloKriEBihoKVhzmcJk9bj@/w![スクリーンショット 2024-12-20 10.50.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1032713/c574263a-2e7f-b22e-7d30-f29fc7120774.png)
cA

スクリーンショット 2024-12-20 10.44.43.png

スクリーンショット 2024-12-20 10.45.21.png

ふむふむ。

スクリーンショット 2024-12-20 10.47.59.png

スタックの動きって頭の中でどうすればわかりやすいのだろう。

スクリーンショット 2024-12-20 10.50.57.png

スクリーンショット 2024-12-20 10.51.46.png

スクリーンショット 2024-12-20 10.52.14.png
スクリーンショット 2024-12-20 10.52.25.png
スクリーンショット 2024-12-20 10.52.34.png
スクリーンショット 2024-12-20 10.52.43.png
スクリーンショット 2024-12-20 10.52.51.png
スクリーンショット 2024-12-20 10.52.58.png
スクリーンショット 2024-12-20 10.53.10.png
スクリーンショット 2024-12-20 10.53.18.png
スクリーンショット 2024-12-20 10.53.27.png
スクリーンショット 2024-12-20 10.53.37.png
スクリーンショット 2024-12-20 10.53.45.png
スクリーンショット 2024-12-20 10.53.57.png
スクリーンショット 2024-12-20 10.54.07.png
スクリーンショット 2024-12-20 10.54.15.png

慣れるとできるようになるのか。練習していけばスラスラできるのかな・・。

forth1の処理系を作ってもらう

スクリーンショット 2024-12-20 11.03.32.png

無茶振り!

スクリーンショット 2024-12-20 11.04.12.png

forth1.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ブラウザ上のForthインタープリタ</title>
    <style>
        body {
            font-family: monospace;
            background-color: #2e2e2e;
            color: #f1f1f1;
            padding: 20px;
        }
        #output {
            width: 100%;
            height: 300px;
            background-color: #1e1e1e;
            color: #f1f1f1;
            padding: 10px;
            overflow-y: scroll;
            white-space: pre-wrap;
            border: 1px solid #555;
            margin-bottom: 10px;
        }
        #input {
            width: 100%;
            padding: 10px;
            background-color: #1e1e1e;
            color: #f1f1f1;
            border: 1px solid #555;
        }
    </style>
</head>
<body>
    <h1>ブラウザ上のForthインタープリタ</h1>
    <div id="output"></div>
    <input type="text" id="input" placeholder="Forthコードを入力してEnterを押してください">
    
    <script>
        class ForthInterpreter {
            constructor(outputCallback) {
                this.stack = [];
                this.words = {
                    '.': () => {
                        if (this.stack.length < 1) {
                            throw new Error("Stack underflow for '.'");
                        }
                        const value = this.stack.pop();
                        outputCallback(String(value));
                    },
                    'dup': () => {
                        if (this.stack.length < 1) {
                            throw new Error("Stack underflow for 'dup'");
                        }
                        const value = this.stack[this.stack.length - 1];
                        this.stack.push(value);
                    },
                    'drop': () => {
                        if (this.stack.length < 1) {
                            throw new Error("Stack underflow for 'drop'");
                        }
                        this.stack.pop();
                    },
                    'swap': () => {
                        if (this.stack.length < 2) {
                            throw new Error("Stack underflow for 'swap'");
                        }
                        const a = this.stack.pop();
                        const b = this.stack.pop();
                        this.stack.push(a);
                        this.stack.push(b);
                    },
                    '+': () => {
                        if (this.stack.length < 2) {
                            throw new Error("Stack underflow for '+'");
                        }
                        const a = this.stack.pop();
                        const b = this.stack.pop();
                        this.stack.push(b + a);
                    },
                    '-': () => {
                        if (this.stack.length < 2) {
                            throw new Error("Stack underflow for '-'");
                        }
                        const a = this.stack.pop();
                        const b = this.stack.pop();
                        this.stack.push(b - a);
                    },
                    '*': () => {
                        if (this.stack.length < 2) {
                            throw new Error("Stack underflow for '*'");
                        }
                        const a = this.stack.pop();
                        const b = this.stack.pop();
                        this.stack.push(b * a);
                    },
                    '/': () => {
                        if (this.stack.length < 2) {
                            throw new Error("Stack underflow for '/'");
                        }
                        const a = this.stack.pop();
                        const b = this.stack.pop();
                        if (a === 0) {
                            throw new Error("Division by zero");
                        }
                        this.stack.push(Math.floor(b / a));
                    }
                };
                this.definitions = {}; // ユーザー定義の単語
            }

            defineWord(name, definition) {
                this.words[name] = definition;
            }

            execute(tokens) {
                for (let token of tokens) {
                    if (/^-?\d+$/.test(token)) { // 整数リテラル
                        this.stack.push(parseInt(token, 10));
                    } else {
                        const word = this.words[token.toLowerCase()];
                        if (word) {
                            word();
                        } else if (this.definitions[token.toLowerCase()]) {
                            this.execute(this.definitions[token.toLowerCase()]);
                        } else {
                            throw new Error(`未知の単語: ${token}`);
                        }
                    }
                }
            }

            interpret(input) {
                const lines = input.split('\n');
                for (let line of lines) {
                    line = line.trim();
                    if (line === '' || line.startsWith('\\')) continue; // 空行やコメントを無視
                    const tokens = line.split(/\s+/);
                    // 簡単な定義処理
                    if (tokens[0].toLowerCase() === ':') {
                        const endIndex = tokens.indexOf(';');
                        if (endIndex === -1) {
                            throw new Error("';' が見つかりません");
                        }
                        const name = tokens[1].toLowerCase();
                        const definition = tokens.slice(2, endIndex).map(t => t.toLowerCase());
                        this.definitions[name] = definition;
                    } else {
                        this.execute(tokens);
                    }
                }
            }
        }

        const outputDiv = document.getElementById('output');
        const inputBox = document.getElementById('input');

        const interpreter = new ForthInterpreter((output) => {
            outputDiv.textContent += output + '\n';
            outputDiv.scrollTop = outputDiv.scrollHeight;
        });

        inputBox.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                const code = inputBox.value;
                inputBox.value = '';
                outputDiv.textContent += `> ${code}\n`;
                try {
                    interpreter.interpret(code);
                } catch (err) {
                    outputDiv.textContent += `Error: ${err.message}\n`;
                }
                outputDiv.scrollTop = outputDiv.scrollHeight;
            }
        });

        // 初期メッセージ
        outputDiv.textContent = "Forth インタープリタへようこそ!\n";
        outputDiv.textContent += "単語を入力してEnterを押してください。\n";
    </script>
</body>
</html>

スクリーンショット 2024-12-20 11.05.38.png
スクリーンショット 2024-12-20 11.06.10.png
スクリーンショット 2024-12-20 11.06.34.png
スクリーンショット 2024-12-20 11.06.42.png
スクリーンショット 2024-12-20 11.06.49.png
スクリーンショット 2024-12-20 11.06.57.png

ほんとうに動くのか?
ブラウザに読み込んで、「使用例」を試してみる。

スクリーンショット 2024-12-20 11.08.58.png

おー、すごい。

終わりに

歴史あるforthは頭の体操・ボケ防止に効果がありそうと思いました。

色々試す過程で、WASMでできた、もっと本格的な処理系も見つけました。

以上、「ChatGPT先生にforthを教えてもらう」でした。

最後までご覧いただきましてありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?