js实现简单计算器词法解析语法解析解释器,带可视化界面

news2025/1/12 20:58:20

代码

Lexer是词法解析器

Parser是语法解析器

Interpreter 是ast解释器

可视化页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lexer, Parser, and Interpreter Visualization</title>
    <style>
        body {
            font-family: Arial, sans-serif;
        }
        #input-container {
            margin-bottom: 20px;
        }
        #lexer-output, #parser-output, #interpreter-output {
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 20px;
        }
        #lexer-output h2, #parser-output h2, #interpreter-output h2 {
            margin-top: 0;
        }
        #lexer-tokens, #parser-ast {
            list-style-type: none;
            padding: 0;
        }
        #lexer-tokens li {
            margin-bottom: 5px;
        }
        #parser-ast ul {
            padding-left: 20px;
        }
    </style>
</head>
<body>
    <h1>Lexer, Parser, and Interpreter Visualization</h1>
    <div id="input-container">
        <label for="input">Input Expression:</label>
        <input type="text" id="input" placeholder="Enter expression...">
        <button onclick="processInput()">Process</button>
    </div>
    <div id="lexer-output">
        <h2>Lexer Output:</h2>
        <ul id="lexer-tokens"></ul>
    </div>
    <div id="parser-output">
        <h2>Parser Output (Abstract Syntax Tree):</h2>
        <pre id="parser-ast"></pre>
    </div>
    <div id="interpreter-output">
        <h2>Interpreter Output (Result):</h2>
        <div id="interpreter-result"></div>
    </div>

    <script>
        function processInput() {
            const input = document.getElementById('input').value;
            
            // Lexer
            const lexer = new Lexer(input);
            const lexerTokens = [];
            let token;
            while ((token = lexer.nextToken()) !== null) {
                lexerTokens.push(token);
            }
            displayLexerOutput(lexerTokens);

            // Parser
            const parser = new Parser(new Lexer(input));
            const ast = parser.parse();
            displayParserOutput(ast);

            // Interpreter
            const interpreter = new Interpreter();
            const result = interpreter.interpret(ast);
            displayInterpreterOutput(result);
        }

        function displayLexerOutput(tokens) {
            const lexerTokensList = document.getElementById('lexer-tokens');
            lexerTokensList.innerHTML = '';
            tokens.forEach(token => {
                const li = document.createElement('li');
                li.textContent = `${token.type}: ${token.value}`;
                lexerTokensList.appendChild(li);
            });
        }

        function displayParserOutput(ast) {
            const parserAST = document.getElementById('parser-ast');
            parserAST.textContent = JSON.stringify(ast, null, 2);
        }

        function displayInterpreterOutput(result) {
            const interpreterResult = document.getElementById('interpreter-result');
            interpreterResult.textContent = `Result: ${result}`;
        }

        class Lexer {
            constructor(input) {
                this.input = input;
                this.position = 0;
            }

            nextToken() {
                while (this.position < this.input.length && /\s/.test(this.input[this.position])) {
                    this.position++;
                }

                if (this.position >= this.input.length) {
                    return null;
                }

                let currentChar = this.input[this.position];

                if (/\d/.test(currentChar)) {
                    let number = '';
                    while (/\d/.test(currentChar) && this.position < this.input.length) {
                        number += currentChar;
                        this.position++;
                        currentChar = this.input[this.position];
                    }
                    return { type: 'NUMBER', value: number };
                }

                if (currentChar === '+') {
                    this.position++;
                    return { type: 'PLUS', value: '+' };
                }

                if (currentChar === '-') {
                    this.position++;
                    return { type: 'MINUS', value: '-' };
                }

                if (currentChar === '*') {
                    this.position++;
                    return { type: 'STAR', value: '*' };
                }

                if (currentChar === '/') {
                    this.position++;
                    return { type: 'SLASH', value: '/' };
                }

                if (currentChar === '(') {
                    this.position++;
                    return { type: 'LPAREN', value: '(' };
                }

                if (currentChar === ')') {
                    this.position++;
                    return { type: 'RPAREN', value: ')' };
                }

                throw new Error(`Unknown character: ${currentChar}`);
            }
        }

        class Parser {
            constructor(lexer) {
                this.lexer = lexer;
                this.currentToken = this.lexer.nextToken();
            }

            eat(tokenType) {
                if (this.currentToken && this.currentToken.type === tokenType) {
                    this.currentToken = this.lexer.nextToken();
                } else {
                    throw new Error(`Expected token type ${tokenType} but got ${this.currentToken ? this.currentToken.type : 'null'}`);
                }
            }

            factor() {
                let token = this.currentToken;
                if (token.type === 'NUMBER') {
                    this.eat('NUMBER');
                    return { type: 'Literal', value: parseInt(token.value, 10) };
                } else if (token.type === 'LPAREN') {
                    this.eat('LPAREN');
                    let node = this.expr();
                    this.eat('RPAREN');
                    return node;
                } else {
                    throw new Error(`Unexpected token: ${token.type}`);
                }
            }

            term() {
                let node = this.factor();

                while (this.currentToken && (this.currentToken.type === 'STAR' || this.currentToken.type === 'SLASH')) {
                    let token = this.currentToken;
                    if (token.type === 'STAR') {
                        this.eat('STAR');
                    } else if (token.type === 'SLASH') {
                        this.eat('SLASH');
                    }
                    node = { type: 'BinaryExpression', operator: token.value, left: node, right: this.factor() };
                }

                return node;
            }

            expr() {
                let node = this.term();

                while (this.currentToken && (this.currentToken.type === 'PLUS' || this.currentToken.type === 'MINUS')) {
                    let token = this.currentToken;
                    if (token.type === 'PLUS') {
                        this.eat('PLUS');
                    } else if (token.type === 'MINUS') {
                        this.eat('MINUS');
                    }
                    node = { type: 'BinaryExpression', operator: token.value, left: node,
                    right: this.term() };
                }

                return node;
            }

            parse() {
                return this.expr();
            }
        }

        class Interpreter {
            interpret(node) {
                if (node.type === 'Literal') {
                    return node.value;
                } else if (node.type === 'BinaryExpression') {
                    const leftValue = this.interpret(node.left);
                    const rightValue = this.interpret(node.right);
                    switch (node.operator) {
                        case '+':
                            return leftValue + rightValue;
                        case '-':
                            return leftValue - rightValue;
                        case '*':
                            return leftValue * rightValue;
                        case '/':
                            if (rightValue === 0) {
                                throw new Error('Division by zero');
                            }
                            return leftValue / rightValue;
                        default:
                            throw new Error(`Unknown operator: ${node.operator}`);
                    }
                } else {
                    throw new Error(`Unknown node type: ${node.type}`);
                }
            }
        }
    </script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1811026.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【启明智显芯片应用】Model3C芯片4.3寸拼图机应用方案

数据显示&#xff0c;618前期&#xff0c;早教启智、智能玩具、科学启蒙、数字阅读类产品销量增长迅猛。当下&#xff0c;90后新生代父母对于孩子的科学启蒙教育愈发重视&#xff0c;他们在给孩子选择学习产品时&#xff0c;越来越倾向于选择寓教于乐的益智类产品&#xff0c;而…

神奇!你见过生成Prompt的Prompt?

目录 先上干货 这个Prompt是怎么来的 道路是曲折的 总结 PART/ 01 先上干货 你怎么会想到这些场景呢&#xff0c;比如健身计划、英语学习、旅游规划等等&#xff0c;其实挺不好意思的&#xff0c;大家被我骗了&#xff0c;这些都是我使用一个Prompt解决的。 对&#xf…

使用OpenLLM在AMD GPU上的分步指南

Step-by-Step Guide to Use OpenLLM on AMD GPUs — ROCm Blogs 引言 OpenLLM是一个开源平台&#xff0c;旨在促进大型语言模型&#xff08;LLMs&#xff09;的部署和使用&#xff0c;支持多种模型&#xff0c;适应不同的应用&#xff0c;无论是在云环境还是本地环境中。在本教…

何为屎山代码?

在编程界&#xff0c;有一种代码被称为"屎山代码"。这并非指某种编程语言或方法&#xff0c;而是对那些庞大而复杂的项目的一种形象称呼。屎山代码&#xff0c;也被称为"祖传代码"&#xff0c;是历史遗留问题&#xff0c;是前人留给我们的"宝藏"…

丽水职业技术学院:以太彩光网络筑基教育信息化标杆之路

丽水职业技术学院作为教育信息化的先行者,是浙江省首批“浙江省高职高水平学校”、“浙江省教育信息化试点校单位”,也是“浙江省数字校园示范校”的一员。学院紧握“十四五”规划契机,全面加速数字化转型,旨在通过基础网络的革新、数字化教学的深化、信息服务的优化、学生管理…

wma和mp3哪个音质好?让我告诉你哪个更胜一筹

在数字音频领域&#xff0c;WMA和MP3是两种常见的音频格式&#xff0c;它们在网络上的音频传输和储存中都扮演着重要的角色。然而&#xff0c;许多人可能会对这两者之间的音质差异产生疑问&#xff0c;想知道哪一个更适合他们的需求。wma和mp3哪个音质好&#xff1f;在本文中&a…

Transformer介绍

Transformer的诞生 2018年Google发出一篇论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》, BERT模型横空出世, 并横扫NLP领域11项任务的最佳成绩&#xff01; 而在BERT中发挥重要作用的结构就是Transformer, 之后又相继出现XLNET&a…

如何制作MapBox个性化地图

我们在《如何在QGIS中加载MapBox图源》一文中&#xff0c;为你分享了在QGIS中加载MapBox的方法。 现在为你分享如何制作MapBox个性化地图的方法&#xff0c;如果你需要最新版本的QGIS及高清图源&#xff0c;请在文末查看获取软件安装包的方法。 新建地图样式 进入Mapbox Stu…

[2024-06]-[大模型]-[Ollama]- WebUI

主要涉及要部署的前端webui是来源于:https://github.com/open-webui/open-webui 正常就使用: docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-web…

MySQL—多表查询—练习(1)

一、引言 上几篇关于多表查询的基本几个部分全部学习完了。 多表查询的基本类型的查询包括以下&#xff1a; 1、内连接&#xff08;隐式内连接、显示内连接&#xff09;&#xff1a;... [INNER] JOIN ... ON 条件; &#xff09; 2、外连接&#xff08;左外连接、右外连接&…

中国蚁剑 安装教程 2024年5月

2024/5/11 中国蚁剑 安装教程 一、下载中国蚁剑的加载器和核心源码&#xff08;两个都要用到&#xff09; github官方下载地址&#xff1a;https://github.com/AntSwordProject/ 参考文档&#xff1a;antSword/README_CN.md at master AntSwordProject/antSword GitHub 核…

iPhone - 为什么姓名和付款都变成灰色?

问题描述 为什么姓名和付款都变成灰色&#xff1f;点开订阅也显示图 2 的无法连接&#xff1f; 原因分析 联网 WIFI 没有对『设置』开放权限。 解决方案 设置 - 无线局域网 - 使用无线局域网与蜂窝网络的App - 找到『设置』应用 - 勾选『无线局域网与蜂窝数据』

品牌渠道健康发展的关键与方法

一个品牌的渠道健康与否对其长期发展至关重要。品牌虽多&#xff0c;但并非所有产品都能成为品牌&#xff0c;创建品牌需大量精力&#xff0c;而让品牌长久健康发展则需多方面努力。 力维网络服务众多知名品牌&#xff0c;总结出一些渠道治理方法供品牌参考。首先&#xff0c;管…

Matlab 2024a 建模基础知识全面指南

一、Matlab简介 1. Matlab是什么&#xff1f; Matlab&#xff08;Matrix Laboratory&#xff09;是由MathWorks公司开发的一个高性能的数值计算环境和编程语言。它以其强大的矩阵运算能力、丰富的工具箱和便捷的数据可视化功能而闻名&#xff0c;广泛应用于科学研究、工程模拟…

IP协议(二)

TOC 一: 网段划分 同一个局域网的主机,要按一定的规则分配IP地址 把一个IP地址分为两部分: 前半部分 ,网络号 >用来表示局域网后半部分,主机号 > 用来区分同一个局域网中的不同主机 同一个局域网内部&#xff0c;主机之间的IP &#xff0c; 网络号相同&#xff0c;主…

进口电动双座调节阀选型-美国品牌

在选型进口电动双座调节阀时&#xff0c;需要综合考虑多个因素以确保选择到最适合的调节阀。以下是一个清晰的选型指南&#xff0c;结合了参考文章中的相关信息&#xff1a; 1. 根据工艺需求确定调节阀类型 流量需求&#xff1a;对于需要大流量调节的场合&#xff0c;双座调节…

选电气还是机械?

电气工程和机械工程都是非常重要的工程领域&#xff0c;但它们确实有不同的特点和就业前景。我这里有一套自动化入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习自动化&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信22&…

基于LangChain的Prompt模板

简介&#xff1a; LangChain是一个开源库&#xff0c;简化了基于LLM的AI应用开发&#xff0c;充当AI开发的万能适配器&#xff0c;抽象并整合了大语言模型&#xff08;如OpenAI和文心&#xff09;的交互。要使用LangChain&#xff0c;首先通过pip install langchain安装。示例展…

还在为复制粘贴烦恼吗?这5个工具帮你轻松搞定

在日常工作中&#xff0c;CtrlC和CtrlV无疑是我们使用最为频繁的快捷键组合。 复制粘贴&#xff0c;轻松快捷。 但是在使用中&#xff0c;也会有一点不便&#xff0c;那就是无法保存剪贴历史内容。 比如我说复制之后&#xff0c;我想要想要找回这一次复制之前的内容&#xf…

2024年,计算机相关专业还值得选择吗?

计算机专业&#xff1a;2024年的热门选择还是明智之选&#xff1f; 随着2024年高考的尘埃落定&#xff0c;许多考生和家长都站在了人生新的十字路口&#xff0c;思考着如何为未来的职业生涯铺设基石。在众多专业中&#xff0c;计算机相关专业始终占据着一席之地&#xff0c;其…