// 实验存档

输入示例

main()
{
int a, b;
a = ;
b = a + ;
}

效果图

全部代码

编辑一份.html文件,将代码拷入,作为网页打开即可使用。

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title>Lexical_Analysis</title>
<link href="https://fonts.googleapis.com/css?family=Noto+Serif+SC" rel="stylesheet">
<style>
main {
/*对子元素开启弹性布局*/
display: flex;
/*弹性元素在必要的时候换行*/
flex-wrap: wrap;
/*将弹性元素居中*/
justify-content: center;
} textarea,
button {
font-family: 'Noto Serif SC', STFangSong, serif;
font-size: 17px;
}
</style>
</head> <body>
<main>
<textarea name="input" rows="20" cols="40"></textarea>
<textarea name="output" rows="20" cols="40"></textarea>
<button name="compile">Lexical Analysis</button>
</main>s <script>
let inputBox = document.querySelector("textarea[name=input]");
let outputBox = document.querySelector("textarea[name=output]");
let btnCompile = document.querySelector("button[name=compile]");
btnCompile.addEventListener("click", event => {
let inputCode = inputBox.value;
outputBox.value = JSON.stringify(Lexical_Analysis(inputCode));
});
/*
* 规则:
识别保留字:if、int、for、while、do、return、break、continue;
单词种别码为1。
其他的都识别为标识符;单词种别码为2。
常数为无符号整形数;单词种别码为3。
运算符包括:+、-、*、/、=、>、<、>=、<=、!= ;单词种别码为4。
分隔符包括:,、;、{、}、(、); 单词种别码为5。
*/
const reservedWords = ['if', 'int', 'for', 'while', 'do', 'return', 'break', 'continue'];
const operators = ['+', '-', '*', '/', '=', '<', '>', '!', '>=', '<=', '!='];
const separators = [',', ';', '{', '}', '(', ')']; function Lexical_Analysis(str) {
/**
* current用于标识当前字符位置,
* str[cur]即为当前字符
*/
let cur = 0;
/**
* tokens存储词法分析的最终结果
*/
let tokens = []; while(cur < str.length) { if(/\s/.test(str[cur])) { // 跳过空格
cur++;
} else if(/[a-z]/i.test(str[cur])) { // 读单词
debugger;
let word = "" + str[cur++];
// 测试下一位字符,如果不是字母直接进入下一次循环(此时cur已经右移)
// 如果是则继续读字母,并将cur向右移动
while(cur < str.length && /[a-z]/i.test(str[cur])) {
// cur < str.length防止越界
word += str[cur++];
}
if(reservedWords.includes(word)) {
tokens.push({
type: 1,
value: word,
}); // 存储保留字(关键字)
} else {
tokens.push({
type: 2,
value: word,
}); // 存储普通单词
}
} else if(separators.includes(str[cur])) {
tokens.push({
type: 5,
value: str[cur++],
}); // 存储分隔符并将cur向右移动
} else if(operators.includes(str[cur])) {
let operator = "" + str[cur++];
if(['>', '<', '!'].includes(operator)) {
// 如果下一个字符是=就添加到operator并再次向右移动cur
if(str[cur] = '=') {
operator += str[cur++];
}
}
tokens.push({
type: 4,
value: operator,
}); // 存储运算符
} else if(/[0-9]/.test(str[cur])) {
let val = "" + str[cur++];
// cur < str.length防止越界
while(cur < str.length && /[0-9]/.test(str[cur])) {
val += str[cur++];
}
tokens.push({
type: 3,
value: val,
}); // 存储整数数字
} else {
return "包含非法字符:" + str[cur];
} }
return tokens;
}
</script>
</body>
</html>

附件,龙书2.6节练习:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
<link href="https://fonts.googleapis.com/css?family=Noto+Serif+SC" rel="stylesheet">
<style>
main {
/*对子元素开启弹性布局*/
display: flex;
/*弹性元素在必要的时候换行*/
flex-wrap: wrap;
/*将弹性元素居中*/
justify-content: center;
} textarea,
button {
font-family: 'Noto Serif SC', STFangSong, serif;
font-size: 17px;
}
</style>
</head> <body>
<main>
<textarea name="input" rows="20" cols="40"></textarea>
<textarea name="output" rows="20" cols="40"></textarea>
<button name="execute">Execute</button>
</main> <script>
let inputBox = document.querySelector("textarea[name=input]");
let outputBox = document.querySelector("textarea[name=output]");
let btnExecute = document.querySelector("button[name=execute]"); btnExecute.addEventListener("click", event => {
let tokens = tokenizer(inputBox.value);
console.log(tokens);
}); function tokenizer(input) {
let s = input;
let cur = 0;
let peek = ' ';
let line = 1;
let words = new Map(); let readChar = () => s[cur++];
let undo = () => cur--;
let scan = () => { // 每次scan返回一个Token
// 略过空格,上次设置的peek值并不会被清空
for (;; peek = readChar()) {
if (peek == undefined) {
return null; // 读完了
} else if (peek == ' ' || peek == '\t') {
continue; // 略过空格和Tab
} else if (peek == '\n') {
line++; // 记录当前行
} else {
break;
}
} // 略过注释
if ('/' == peek) {
peek = readChar();
if ('/' == peek) {
// 注释类型1
peek = readChar();
for (;; peek = readChar()) {
if (peek == '\n') {
break; // 正常退出
} else if (peek == undefined) {
return null; // 读完了,正常退出
}
}
} else if ('*' == peek) {
peek = readChar();
// 注释类型2
let lastAsterisk = false;
for (;; peek = readChar()) {
if (peek == undefined) {
console.log("注释语法错误01");
return null; // 语法错误
} else if (peek == '\n') {
lastAsterisk = false;
line++; // 记录当前行
} else if (peek == '*') {
lastAsterisk = true;
} else if (lastAsterisk && peek == '/') {
peek = readChar();
break; // 正常退出
} else {
lastAsterisk = false;
}
}
} else {
// 语法错误
console.log("注释语法错误02");
return null;
}
} // 略过空格,上次设置的peek值并不会被清空
for (;; peek = readChar()) {
if (peek == undefined) {
return null; // 读完了
} else if (peek == ' ' || peek == '\t') {
continue; // 略过空格和Tab
} else if (peek == '\n') {
line++; // 记录当前行
} else {
break;
}
} if (/[0-9.]/.test(peek)) {
let temp = peek;
let hasPoint = false;
if (peek == '.') hasPoint = true;
while (/[0-9.]/.test(peek = readChar())) {
if (peek == '.' && hasPoint) {
console.log("语法错误3,包含多个小数点");
return null;
} else if (peek == '.') {
hasPoint = true;
temp += peek;
} else {
temp += peek;
}
}
return {
tag: 'NUM',
value: Number(temp),
};
} if (/[a-zA-z]/.test(peek)) {
let temp = peek;
while ((peek = readChar()) && /[a-zA-z]/.test(peek)) {
// 经测试,null和undefined都能通过/\w/以及/[a-zA-z]/,并可以转化为字面字符串
temp += peek;
}
let w = words.get(temp);
if (w != undefined) {
return w;
} else {
w = {
tag: 'ID',
lexeme: temp,
};
words.set(temp, w);
return w;
}
} if (/[><=!]/.test(peek)) {
let first = peek;
peek = readChar();
if (peek == '=') {
peek = readChar(); // 避免重复处理
return {
tag: '逻辑运算符',
value: first + '=',
};
} else if (first != '=') {
return {
tag: '逻辑运算符',
value: first,
};
} else { // 单个=的情况,回溯
undo();
peek = first;
}
} let res = {
tag: peek,
};
peek = ' ';
return res;
}; let tokens = [];
let token;
while (token = scan()) {
tokens.push(token);
}
return tokens;
}
</script>
</body> </html>

编译原理 #01# 简易词法分析器(js实现)的更多相关文章

  1. 编译原理 #02# 简易递归下降分析程序(js实现)

    // 实验存档 截图: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  2. 编译原理-一种词法分析器LEX原理

    1.将所有单词的正规集用正规式描述 2.用正规式到NFA的转换算 得到识别所有单词用NFA 3.用NFA到DFA的转换算法 得到识别所有单词用DFA 4.将DFA的状态转换函数表示成二维数组 并与DF ...

  3. 编译原理(简单自动词法分析器LEX)

    编译原理(简单自动词法分析器LEX)源程序下载地址:  http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...

  4. <编译原理 - 函数绘图语言解释器(1)词法分析器 - python>

    <编译原理 - 函数绘图语言解释器(1)词法分析器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 解释器分为三个实现块: 词法分析器: ...

  5. 前端与编译原理 用js去运行js代码 js2run

    # 前端与编译原理 用js去运行js代码 js2run 前端与编译原理似乎相隔甚远,各种热门的框架都学不过来,那能顾及到这么多底层呢,前端开发者们似乎对编译原理的影响仅仅是"抽象语法树&qu ...

  6. 编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器

    编译原理实战--使用Lex/Flex进行编写一个有一定词汇量的词法分析器 by steve yu 2019.9.30 参考文档:1.https://blog.csdn.net/mist14/artic ...

  7. 《编译原理》构造与正规式 (0|1)*01 等价的 DFA - 例题解析

    <编译原理>构造与正规式 (0|1)*01 等价的 DFA - 例题解析 解题步骤: NFA 状态转换图 子集法 DFA 的状态转换矩阵 DFA 的状态转图 解: 已给正规式:(0|1)* ...

  8. 前端与编译原理——用JS写一个JS解释器

    说起编译原理,印象往往只停留在本科时那些枯燥的课程和晦涩的概念.作为前端开发者,编译原理似乎离我们很远,对它的理解很可能仅仅局限于"抽象语法树(AST)".但这仅仅是个开头而已.编 ...

  9. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

随机推荐

  1. 洛谷 P3379 【模板】最近公共祖先(LCA)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  2. 电子产品使用感受之——为什么我把Apple Watch S2 升级到了 S4?

    2019.03.14 更新 最近在手表上安装了“摩拜单车”的APP,这绝对是一款使用体验加分的APP. 我每天上下班都要骑摩拜单车,但是每次掏出手机,首先FACE ID解锁屏幕,然后从上往下滑屏幕来触 ...

  3. 20175320 2018-2019-2 《Java程序设计》第6周学习总结

    20175320 2018-2019-2 <Java程序设计>第6周学习总结 教材学习内容总结 本周学习了教材的第七及第十章的内容.在这两章中介绍了接内部类与异常类以及输入.输出流,第七章 ...

  4. tomcat 启动方式

    <?xml version="1.0" encoding="UTF-8"?><Context docBase="wexin" ...

  5. flask基础三

    一.路由和视图(基础二上补充) (1)有参装饰器 路由采用的是有参装饰器实现的 @app.route("/index",methods=["GET"," ...

  6. es6的对象新增的方法

    Object.is 可以看成是=== 的加强版, 其修正了 === 的 NaN 不等于自身, 以及 +0 等于 -0 另外说下, == 会自动转型, 但是 Object.is 也是如果类型不一致也是不 ...

  7. Excel文件导入导出(基于Nodejs、exceljs)

    Excel导入.导出是大多数项目的管理后台必备功能.几年来使用过多个该功能的实现包,最近一次开发该功能,突然发现一个人气极高(3000+)的包,这里记录一下使用方法. 大凡厉害的技术的文档咋一看都想字 ...

  8. Linux-centos7下python3 环境设置

    首先安装依赖包 yum -y groupinstall "Development tools" yum -y install zlib-devel bzip2-devel open ...

  9. cnblogs

    想注册个博客园来着的,看着大佬们的博客都十分漂亮,但是发现我因为太菜没有办法搞定美化问题. 以后再说吧 写写东西,反正也没人看,但是写的时候尽量按给别人看的格式写吧 2019.3.15 开通博客 计划 ...

  10. golang的包管理---vendor/dep等

    首先关于vendor 1 提出问题 我们知道,一个工程稍大一点,通常会依赖各种各样的包.而Go使用统一的GOPATH管理依赖包,且每个包仅保留一个版本.而不同的依赖包由各自的版本工具独立管理,所以当所 ...