首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

我的lexer是不是做得太多了--它做的是解析器的工作吗?

Lexer(词法分析器)和Parser(解析器)是编译器或解释器中的两个不同组件,它们各自承担不同的任务。

基础概念

Lexer(词法分析器)

  • 任务:将输入的字符流分解成一系列有意义的标记(tokens)。
  • 输出:一系列的标记(tokens),每个标记代表一种语法单元,如关键字、标识符、运算符等。

Parser(解析器)

  • 任务:根据语法规则,将词法分析器生成的标记序列转换成抽象语法树(AST)或其他中间表示。
  • 输出:抽象语法树(AST)或其他中间表示,用于后续的语义分析和代码生成。

相关优势

Lexer的优势

  • 模块化:词法分析相对独立,易于维护和扩展。
  • 效率:词法分析通常比语法分析更快,因为它只需要识别简单的模式。

Parser的优势

  • 结构化:解析器生成的抽象语法树提供了程序的结构化表示,便于后续处理。
  • 灵活性:通过修改语法规则,可以轻松支持不同的语言特性。

类型

Lexer的类型

  • 手工编码:根据具体需求手动编写词法分析器。
  • 工具生成:使用工具如Flex(C/C++)、Jison(JavaScript)等自动生成词法分析器。

Parser的类型

  • 递归下降解析器:手工编写,简单直观,但难以处理复杂的语法规则。
  • LR解析器:使用工具如Bison(C/C++)、ANTLR(多种语言)等生成,能够处理复杂的语法规则。

应用场景

Lexer的应用场景

  • 编译器和解释器:用于将源代码分解成标记,供解析器使用。
  • 文本处理工具:如日志分析、数据提取等。

Parser的应用场景

  • 编译器和解释器:用于将标记序列转换成抽象语法树,进行语义分析和代码生成。
  • 配置文件解析:如JSON、XML等格式的解析。

可能遇到的问题及解决方法

问题:Lexer做了太多工作,是否在做解析器的工作?

  • 原因:可能是词法分析器的设计过于复杂,或者在词法分析阶段进行了本应在解析阶段完成的工作。
  • 解决方法
    • 简化词法分析器:确保词法分析器只负责识别标记,不涉及语法结构的判断。
    • 分离关注点:将词法分析和语法分析明确分开,确保每个组件只做自己的工作。
    • 使用工具:考虑使用现有的词法分析器和解析器生成工具,如Flex和Bison,它们已经经过优化,能够很好地处理这些任务。

示例代码

假设我们有一个简单的编程语言,包含关键字ifelse,标识符和基本运算符。我们可以使用Flex生成词法分析器,使用Bison生成解析器。

Flex词法分析器示例

代码语言:txt
复制
%{
#include "parser.tab.h"
%}

%%

"if"    { return IF; }
"else"  { return ELSE; }
[a-zA-Z_][a-zA-Z0-9_]* { yylval.str = strdup(yytext); return IDENTIFIER; }
[ \t\n] ; /* ignore whitespace */
.       return yytext[0];

%%

int yywrap() {
    return 1;
}

Bison解析器示例

代码语言:txt
复制
%{
#include <stdio.h>
#include <stdlib.h>
%}

%union {
    char *str;
}

%token <str> IDENTIFIER
%token IF ELSE

%%

program:
    | program statement
    ;

statement:
    IF condition THEN statement ELSE statement ENDIF
    | IDENTIFIER '=' expression ';'
    ;

condition:
    IDENTIFIER
    ;

expression:
    IDENTIFIER
    ;

%%

int main(int argc, char **argv) {
    yyparse();
    return 0;
}

void yyerror(const char *s) {
    fprintf(stderr, "Error: %s\n", s);
}

参考链接

通过上述方法,你可以确保Lexer和Parser各自承担合适的任务,避免功能重叠和混淆。

相关搜索:我捕获表单上的提交按钮的代码可以工作,但是我做得正确吗?API回调是如何工作的,我如何实现它?主引导过程是如何工作的,我如何调试它?#if是如何工作的?我误解了#if~#endif的形式吗?有人能告诉我我的RXJS代码是如何工作的吗?我的方法和函数做同样的事情,但是只有函数可以工作吗?什么是WriteResult中的"getUpsertedId“,我可以避免创建它吗?我对这个伪代码的理解是正确的吗?如果是这样,我该如何计算它的大量theta?急切加载如何工作?我的意思是我知道它的作用是什么,但我可以通过做一个'侧'查询来复制它吗?向量的begin()和end()是如何工作的,我应该如何为我的自定义向量编写它?我收到firebase权限错误。即使我是根据firebase规则来做的,它也不能工作我的节点代码不能工作是因为我使用的是windows而不是linux吗?我想在HTML文件中编码我的服务工作者,我可以这样做吗?我的actionlistener不在我的多类/框架Java项目中工作,有人能帮我修复它吗?我的图像滑块在我的基于wordpress的网站主题上不工作使用的是FOX吗?我可以从新的xcode 8上传构建吗?我的故事板是在xcode 6中创建的。苹果会批准它吗?如果窗口小部件是它的子级,listview不能在flutter中工作吗?gschemas.compiled架构是特定的吗(我可以把它和我的python库一起发布吗)?ActiveSheet.AutoFilter.ApplyFilter是必要的吗?当工作表受到保护时,它会破坏我的代码,所以我可以安全地省略它吗?函数中的return语句是如何工作的?我可以使用多个返回语句吗?
相关搜索:
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

刚做测试工作一年的时候,我是怎样的?

03 关于工作 当时发的offer是测试,后来入职后发现是个运维的活。组长是测试经理,算我就俩测试,刚开始写过验收文档,用户操作手册,测试用例,测试计划,写完就写完了,并没人告诉我对不对。...在公司一年下来我发现自己黑眼圈明显严重不少,而且下不去了,直到现在也是如此,后来总有朋友打趣说我是不是纵欲过度了,然后我们就是哈哈大笑… 04 关于爱情 我是毕业就分手了,也许是作为毕业后,必须经历的,...…… 依稀还记得,我师父在年会喝酒喝多了说的一句话。...,我做.net开发?...但如果不坚持下去,永远没有能得到自信的那一天,一辈子都会有挫败感。 坚持做自己认为对的事,至于是对是错,并不重要,时间长了,自然就会有有分晓。

61410

Antlr实战之JSON解析器slowjson

它的主要作用就是你可以用巴科斯范式来描述语法规则,然后它帮你生成对应的解析器。 大家都知道实践是最好的学习方式,要快速深刻地理解antlr的操作和相关接口就不得不找一个练手的东西。...咱写不出来比fastjson更快、bug更少、更安全的json解析器,难道还写不出来一个bug更多、更慢、更不安全的解析器吗,正面拼不赢咱反其道而行。...为了对标阿里的fastjson,我给它起名 slowjson,源码已在github slowjson 欢迎star。为了推广slowjson,我都想好广告词了。 你想升职加薪吗?...你想拿年终奖吗? 你想成为同事眼中的性能优化小能手吗? 今天用slowjson,年底做性能优化换回fastjson,十倍性能不是梦,升职加薪准能成。...,而且简单多了,我的封装如下。

1.4K10
  • 为了拒绝做重复的事情,我用python写了个自动化脚本,让它按名称自动创建工作表

    我是锋小刀! 在上一期视频中,我们讲解了excel如何按指定名称快速创建工作表,没有看的可以看一下:excel按指定名称快速创建工作表。...而python其实也是可以做到的,而且很简单,只需要几行代码即可。而python代码是可以重复利用,能节省很多时间,做到解放双手,拒绝做重复的事情。...xlwt库 今天主要用到xlwt库来操作,xlwt是Python中操作Excel的一个库,可以将进行创建工作簿、工作表、数据写入Excel。在写爬虫时我们也用过,主要是用来保存爬取的数据的。...xlwt库是python的第三方库,需要安装,安装命令: pip install xlwt 实战代码 这里我创建了一个名为"名称"的文件,里面一共有996条数据。 ? 先导入xlwt库。...批量操作文件,解放双手,拒绝做重复的事情,让一些重复的事情不再重复! THE END

    82730

    Boost.Spirit 初体验

    使用代码生成代码是一件十分美妙的事情,于是有了各种代码生成器。但是生成代码,意味着要有对生成规则的分析和处理。 Boost.Spirit 就是这么一个语法分析工具,它实现了对上下文无关文法的LL分析。...Boost.Spirit 的使用真的是把模板嵌套用到了极致。确实这么做造成了非常强的扩展性,生成的代码也非常高效,但是嵌套的太复杂了,对于初学者而言真心难看懂。...你能想象在学习阶段一个不是太明白的错误导致编译器报出的几十层模板嵌套错误信息的感受吗?而且,这么复杂的模板嵌套还直接导致了编译速度的巨慢无比。...其实在之前,我已经使用过Spirit的Classic版本,即1.X版本,但是过多的复制操作让我觉得当时用得很低效,还好分析的内容并不复杂所以没。体现出来 这回就来研究下功能更强劲的2.X 版本。...而Boost.Spirit的Lex库的很多地方和它很像(我也没用过Flex,官方是这么说的)。 Lex的好处呢,就是可以用正则表达式描述一个规则,而且可以动态生成。而且可以可Qi混合起来使用。

    90440

    Boost.Spirit 初体验

    Boost.Spirit 就是这么一个语法分析工具,它实现了对上下文无关文法的LL分析。支持EBNF(扩展巴科斯范式)。 Boost.Spirit 的使用真的是把模板嵌套用到了极致。...确实这么做造成了非常强的扩展性,生成的代码也非常高效,但是嵌套的太复杂了,对于初学者而言真心难看懂。 你能想象在学习阶段一个不是太明白的错误导致编译器报出的几十层模板嵌套错误信息的感受吗?...其实在之前,我已经使用过Spirit的Classic版本,即1.X版本,但是过多的复制操作让我觉得当时用得很低效,还好分析的内容并不复杂所以没。体现出来 这回就来研究下功能更强劲的2.X 版本。...这里面也描述了Qi的解析器支持的操作符。...而Boost.Spirit的Lex库的很多地方和它很像(我也没用过Flex,官方是这么说的)。 Lex的好处呢,就是可以用正则表达式描述一个规则,而且可以动态生成。而且可以可Qi混合起来使用。

    3.3K10

    Kotlin 的 val list: ArrayList= ArrayList() 居然报错!

    想要验证这个其实并不难,我们找到 Kotlin 的源码,找到 lexer 相关的源码: ?...我们看下调用堆栈,解析器被调用的地方实际上是 PsiElement 构造的过程中。我们再来看看 doParseContents 这个方法是干什么的: ?...3 对比看看其他语言 能够出现类似语法的,我们可以对照一下 Swfit 和 Scala。 先说说 Scala,它的解析器应该是极其强大的,毕竟人家允许各种字符作为运算符啊。。 ?...好啦,其实这都不是什么大问题了,这篇文章探讨的那句代码本身就比较蛋疼: val list: ArrayList= ArrayList() 我就问你为什么不去掉前面的类型,类型推导难道还不够吗...还有我觉得Scala 用[ ]来表示泛型比好多了我以前看一个人说后者写起来感觉很反人类或者看上去很奇怪,我很赞同。

    1.3K10

    使用普拉特分析法解析极为复杂的算术表达式

    ”-5”后才能参与运算,并且编译器要知道,add(6,7)是一个函数调用,它需要执行add(6,7),获得函数运行后返回值才能继续参与算术表达式的运算。...好在普拉特解析法有别与传统的编译原理语法解析算法,它简单,精致,易理解,我们看看普拉特解析法是如何巧妙的解决上面复杂算术表达式的解析的。...,它表示做取反操作,this.lexer.MINUS_SIGN 对应表达式中的”-“,它表示做取负操作。上面代码表示,一旦语法解析器解析到符号”!”...然后前序表达式在去掉前序操作符后,接着的确是一个算术表达式,也就是说前序表达式包含了算术表达式,这就形成一个概念定义上的反复包含,我包含你与此同时你又包含我,这种成分的互相包含性是编译原理理解起来的难点所在...,也就是解析器会先处理”56”,再把所得结果与前面的表达式”4”做加法运算。

    1.1K30

    reactjs自制Monkey语言编译器:解析组合表达式,ifelse语句块和间套函数调用

    编译原理也是如此,为了打破这些虚有其表的假道学,我开启了一个用java开发一个实打实的C语言编译器课程,这个编译器能把C语言转换成java字节码,在java虚拟机上执行,我相信这点我绝对是国内首创。...然而让我意象不到的是,原本看似极为复杂的工程实践,原来还存在着相当优美简洁的实现办法,我们这几节所讲的普拉特解析法就是典型实例,原来我需要花几千行代码,费时费力,绞尽脑汁好几天才能完成的事情,在普拉特解析法里就能轻而易举的处理掉...在该函数中,它判断当前解读到的token是否是true,如果是,它会创建一个Boolean类,把它的value值设置成1,若不然,把value值设置成0,上面代码完成后,程序运行结果如下: ?...,它先判断关键字”fn” 之后是不是跟着左括号,如果是,那么根据函数定义,接下来就是以逗号分隔开的参数列表,参数列表的解析由函数parseFunctionParameters负责,由于函数可以没有参数,...因此在它的执行中,先判断左括号后面是不是直接跟着右括号,如果是那就直接返回。

    46930

    【Python】Ply 简介

    包含太多特殊规则了,对于一个不了解 ply 的人来说,这可能太糟糕了,我们需要一些办法来稍稍改善它。...你可以在单独的模块中定义规则,以此保证分析器主代码干净,这需要你在创建 lexer 时显式地指定 module: lexer = lex.lex(module=tokrules) 面向对象:有时面向对象不失是一个封装的好办法...# or parser = yacc.yacc(start="foo") 移入/规约 上面给出的语法规则是经过规约的规则,对解析器来说,它更容易处理,因为它几乎不存在歧义,但从编程的角度来说,我们可能会以一种更符合人类直觉的方式定义语法规则...解析器是依赖堆栈工作的,阅读时注意栈顶在靠右 文件中用 ! 标注出了冲突的地方,虽然这些冲突不见得都是不好的。...其他 一个良好的解析器不应该遇到错误就立刻返回,你应该尽可能返回所有的错误以便用户排查错误,你可以定义 p_error 来处理异常,它将以发生错误的 TOKEN 作为参数,在这里你可以做一些恢复错误的操作

    2.8K30

    Reactjs开发自制编程语言Monkey的编译器:语法解析

    例如下面这条语句: let foo = 1234; 语句经过词法解析器解析后,就会转变为: LET IDENTIFIER ASSIGN_SIGN INTEGER SEMI 完成上面工作后,词法解析器的任务就完成了...我们本节将实现一个简单的语法解析器,它的作用是能解析let 语句,例如: let foo = 1234; let x = y; 语法解析器在实现语法解析时,一般有两种策略,一种叫自顶向下,一种是自底向上...,需要传入词法解析器,因为解析器解析的内容是经过词法解析器处理后的结果,也就是一系列token的组合。...this.expectPeek(this.lexer.IDENTIFIER)) { return null } 上面代码用于判断,跟着关键字let 后面的是不是变量字符串...如果是就用当前的token构建一个Identifier类,并把它作为初始化LetStatement类的一部分。接下来就得判断跟着的是否是等号了: if (!

    91920

    我PUA你了么

    如果从这个角度上看,有些人肯定会认为我是PUA了他。但真的是这样的吗? 03 我只是想把事做得更好而已,有错吗?上级对自己的要求多一些,高一些,真的是在PUA我吗?想了很久,终于想通问题出在哪里了。...问题就在于:是谁来做PUA这个动作!! 如果是上级强制要求测试来做质量内建,做不好就滚蛋,那这个就是在PUA了。但如果是我自己想把事做得更好些,让团队质量更好些,就不算是PUA了吧。...04 回想自己的成长历程,虽然不能说是把工作当成了义务,但至少也是会经常思考如何把事做得更好,很少去想这件是不是应该我去做。 功能测试人员要学性能测试吗?...05 有一位教练和我说,在团队,要做到“职责是明确的,边界是模糊的”,什么意思呢,就是每个岗位都是自己明确的工作职责,但是,谁来做这事,可以是模糊的。...不要因为角色结束了自己,也不要计较一时的付出是多还是少,事就在哪,你不做,总有人来做。那为什么不是你去做呢?你的付出团队是看得见的,它总能在某个关键时刻帮助到你。 教练说得对!

    34210

    深入解析 Java 中的 SQL 解释器树设计与实现

    哈喽,各位小伙伴们,你们好呀,我是喵手。...我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀...本文将详细介绍 SQL 解释器树的实现方法,帮助开发者理解 SQL 解析器的工作原理,掌握如何在 Java 中构建和使用 SQL 解释器树。...本文将探讨 SQL 解析器树的设计与实现,涵盖源码解析、使用案例、应用场景、优缺点分析等方面,帮助 Java 开发者深入理解 SQL 解释器树的工作原理和应用。...小结:这个测试用例的目的是确保SQL解析器能够正确地解析一个简单的SQL查询语句,并生成一个符合预期的AST。

    14723

    Go 译文之词法分析与解析 Part Two

    词法器的职责是读取 INI 文件内容、分析创建 Token,以及通过 channel 将 Token 发送给解析器。...接着,将 Token 和 Token 类型通过 channel 发送给解析器。 最后,判断下一个期望的状态函数,并返回。 我们先定义一个启动函数。它同样是解析器(下篇文章)的启动入口。...它初始化了一个 Lexer,赋予它第一个状态函数。 第一个期望的 Token 可能是什么?一个特殊符号还是一个关键词?...LexSection 返回的状态函数是 LexerRightBracket,逻辑与 LexerLeftBracket 类似,不同的是,它返回的状态函数是 LexBegin, 原因是 Section 可能是空...它会在遇到换行符时确认一个完整的Value。它返回的状态函数是 LexBegin,以此继续下一轮的分析。

    49320

    语法解析的基本原理和快速上手实践

    一种直观的做法是我们依次读入字符然后做即时判断,例如首先看第一个读到的字符是不是数字,或者是不是左括号,然后根据读入的前一个字符看看接下来读入的字符是否合法,你可以尝试用代码来实现试试,你很快会发现代码非常难写...算法的基本做法是选择相应的生产式进行”套用“,直到生产式解析为终结符为止。于是对应表达式3+2,我们可以猜到可以使用list -> list + list, 因为只有它含有符号”+”。...我个人觉得很难用语言来描述什么叫语法,但我发现如果使用代码的话,或许能让人有“心领神会”的感觉。...由于语法解析不好用语言说明,有意思的是使用代码反而能描述更清楚,因此我们直接通过代码来理解如何使用生产式来匹配给定的字符串,首先我们对上次完成的lexer做一些修改: package lexer import...,例如在使用list -> “(“ list “)”,时,代码首先判断读入的是不是左括号,然后递归的调用list函数字节,最后再判断最终读入的是不是右括号,所以生产式本质上是指导我们代码如何实现,代码对读入字符的判断

    31420

    使用普拉特解析法解析复杂的算术表达式

    解析器还得考虑不同操作符产生不同含义的表达式,例如 -5 表示的是一个数值也就是负五,而—5 表示的是一次算术操作,意思是计算5-1所得的值,也就是4....,由于算术表达式展现形式多种多样,要通过它光怪陆离的表象识别它的本质是一件很困难的事情,因此,语法解析器对算术表达式解析算法的发明和实现是计算机科学发展史上光辉的一页。...} } 我们提到的函数表就是prefixParseFns, 从代码可以看成,如果解析器当前遇到的token类型是变量字符串,也就是lexer.IDENTIFIER,时,解析器就从该表中拿出...parseIdentifier这个函数来执行,如果解析器当前遇到的token类型是数组字符串,那么它便从该表中拿出函数parseIntegerLiteral来执行。...如果当前解析器读取到的是数字字符串,那么它会从表中找到函数parseIntegerLiteral来执行,该函数根据当前token,把它的内容解析成整形数值后,创建一个IntegerLiteral的类实例

    1.5K20

    【自然框架】之通用权限:用PowerDesigner重新设计了一下数据库,有ER图和表关系图

    好像以前做的那个数据库设计大家都没太看懂,究其原因似乎大家都比较习惯使用PowerDesinger来设计。...我们可以建立一个业务员角色,设置业务员角色可以做的事情,然后把五个业务员和业务员角色关联起来。这样就方便了,业务员可以做得事情有变化的时候,我只需要修改业务员角色可以做得事情就可以了。...而且也可以适合很大的范围,因为那个资源的定义实在是太广泛了,到了无所不包的程度了。但是这个设计真的好吗?或者是实用吗?...我还是觉得看中文舒服:) 3、写这个的目的:  给自己用,工作7年的工作总结、思路总结,四、五个项目的权限的总结。  和大家分享,交流。看看大家的意见,否则不就更是闭门造车吗?...是不是要修改表结构了呢?我是不想改的,还是用角色绑定的方法来处理,增加一个“张三专用角色”,这个角色是“隐藏”的,不和其他的角色一样的管理,需要通过对“张三”来管理。

    2.6K70

    试用GO开发python编译器:实现词法解析

    下面我们完成一个基本功能的词法解析器,在lexer文件夹下面新建一个文件为lexer.go,输入内容如下: package lexer type Lexer struct { input string...byte //读取的字符 } func New(input string) *Lexer { //生成一个词法解析器 l := &Lexer{input: input} return...int //下一个要读取的字符位置,也就是position + 1 ch byte //读取的字符 } func New(input string) *Lexer { //生成一个词法解析器...,后面跟着数字或者是下划线,因此解析逻辑就是,当我们读取到字符时,我们就进入到变量名的识别流程,也就是读取到字符后,如果接下来读取的还是字符,数字或者是下划线,我们就不断的往下走,直到遇到不是字符,数字或下划线的符号为止...Python代码做初步的解析了。

    54830

    Go 译文之词法分析与解析 Part Three

    译者前言 最近发现我的翻译是越来越随性了,刚开始文章翻译的时候比较拘束,现在更多强调可读性,比如有些对文章大意没有什么影响的文字我现在都会选择直接跳过。...第二篇文章,英文原版,因主要聚焦在 Lexer 的实现。它完成了将输入文本转化为 Token 的过程。 今天是本系列的最后一篇文章,最终完成我们的解释器。...解析器 解析器的编写,我们要做的第一件事是,创建一个用于存放解析结构的变量,即一个 IniFile 结构体类型变量。...,还有解析器当前的状态。...词法分析与解析是一个非常复杂的话题,有太多内容需要学习。我们可以看到,即使像上面 INI 文件解析这样简单的工作,我们也需要花费一些精力才能完成。

    39320
    领券