终端:
#document BEGIN,#document END#head BEGIN,#head END,#Title BEGIN,#Title END,#ParaGRAPH BEGIN,#ParaGRAPH END,#BolD BEGIN,#BolD END,#ITAliCS BEGIN,#ITAliCS END,#List BEGIN,#List END,#ITEM BEGIN,#ITEM END,#link BEGIN,#TEXT,#ADDRESS,#link END,#define BEGIN,#name,#VALUE,#define END,#USE BEGIN,#USE END
请注意,这些终端不区分大小写.
非终端:
<document> ::= #document BEGIN <macro-‐define> <head> <body> #document END<head> ::= #head BEGIN <Title> #head END | ε<Title> ::= #Title BEGIN <text> #Title END | ε<body> ::= <inner-‐text> <body> | <paragraph> <body> | <bold> <body> | <italics> <body> | <List> <body> | ε<paragraph> ::= #ParaGRAPH BEGIN <macro-‐define> <inner-‐paragraph> #ParaGRAPH END<inner-‐paragraph> ::= <inner-‐text> <inner-‐paragraph> | <bold> <inner-‐paragraph> | <italics> <inner-‐paragraph> | <List> <inner-‐paragraph> | ε<inner-‐text> ::= <macro-‐use> <inner-‐text> | <text> <inner-‐text> | ε<macro-‐define> ::= #define BEGIN #name <text> #VALUE <body> #define END <macro-‐define> | ε<macro-‐use> ::= #USE BEGIN <text> #USE END | ε<bold> ::= #BolD BEGIN <macro-‐define> <inner-‐text> #BolD END<italics> ::= #ITAliCS BEGIN <macro-‐define> <inner-‐text> #ITAliCS END<link> ::= #link BEGIN #TEXT <text> #ADDRESS <text> #link END<List> ::= #List BEGIN #ITEM BEGIN <macro-‐define> <inner-‐List> #ITEM END <List-‐items> #List END<List-‐items> ::= #ITEM BEGIN <macro-‐define> <inner-‐List> #ITEM END <List-‐items> | ε<inner-‐List> ::= | <bold> <inner-‐List> | <italics> <inner-‐List> | <List><inner-‐List> | <inner-‐text> <inner-‐List> | ε<text> ::= Any plain text | ε
我们可以假设诸如“<”,“>”,“&”和“/”之类的HTML字符不出现在源文件的任何文本中.我们还可以假设“#”仅出现在我们的一个Markdown注释之前(例如,#document).我认为最好有单独的java类来表示令牌对象,例如:documentBegin,documentEnd,ParagraphBegin,ParagraphEnd等.遇到的任何词汇错误(例如,#DOC BEGIN)都应该作为输出报告给控制台错误信息尽可能.遇到第一个错误后,编译器应该退出.如果遇到错误,则不应创建输出文件.
我的问题是,我知道词法分析器应该做什么,但老实说,我不知道从哪里开始编码/实现.如果您需要更多解释问题的原因,请询问,我可以尽力解释.这是我们班上应有的一个大项目的一部分.我无法完成这部分并且失去了很多分,但现在我只需要了解它,所以一旦我们对它进行了测试,我就不会迷失方向.
解决方法 好的,这已经晚了一点,但我们走了.词法分析器通常与语法(和BNF表示法)相关联,但两者实际上有点不同.
词法分析器将字符转换为令牌,令牌在某种程度上处理语法的“原子”,而解析器将令牌转换为某种中间结构(通常是树).只关注词法分析器部分,您可以将其视为输入的低通处理,就像我们将字母处理成单词一样.
由于您已经拥有BNF语法,因此您已经知道要使用的所有令牌(结束词),因此请将它们放入列表中.这个想法是如何快速决定哪个系列的字母将映射到列表中的每个项目.例如
#,D,E,F,I,N,<whitespace> => #define#,O,C,U,M,T,<whitespace> => #documentB,G,<whitespace> => BEGINE,<whitespace> => END
在解析过程中会出现一些问题:
首先,你要做很多比较.读入的第一个字符可能是’#’,如果是,那么您仍然可以匹配超过20个项目.这意味着你必须继续你的匹配到下一个角色,如果它是’D’仍然意味着有两个可能的匹配’#define’和’#document’.
其次,如果你在处理’#BEGIN’之后有’#BEGIN’和’#BEGINNING’这样的词,那么在你抓住下一个字符之前,你无法决定两者之间的关系.抓住系统中的下一个字符,认为该字符的“消耗”使下一个令牌的处理变得复杂.可能需要窥视或前瞻,但这些增加了逻辑中的复杂性以决定生成哪些令牌.
第三,你有一个外卡“文本”令牌.该令牌几乎可以匹配任何内容,因此您需要针对所有其他令牌进行检查,以确保令牌生成逻辑始终知道它应生成哪个令牌.
理想情况下,令牌生成器(Lexer)不依赖于任何解析来“知道”下一个令牌;然而,有些语言非常复杂,解析器会向Lexer提供“提示”.避免使用这些类型的系统可以实现更清晰的编译器实现;遗憾的是,在一些已有的语言中,并不总是可以用这种方式构建东西.
所以,要知道你知道该怎么做(在某种意义上你可能已经拥有过),你是怎么做到的?
好吧,你需要某种索引来跟踪你消耗的字符(已经完全转换为标记),这样你就不会意外地让字符对令牌流产生双重影响.如果你要向前看,你需要一个“向前看”的第二个指针,你可能想要限制前瞻的数量(使逻辑变得更加困难).
然后,您需要未知数量的数据结构(称为令牌).虽然并非总是需要这样做,但我建议跟踪令牌中的起始行号,起始字符索引,结束行号和结束字符索引.它使调试变得更容易.此外,最好“捕获”令牌中的子字符串.你可以这么称呼你,但有些人称之为令牌的“形象”.
当然,如果您的解析器可以区分不同类型的令牌,那么您应该通过某种方式将该令牌的类型存储在令牌中(或与令牌中).偶尔一个人有一个标记“价值”的概念,它也可能存储.
经过一番努力之后,你应该能够将一串字符推入Lexer,然后出现一系列令牌.祝好运.
总结以上是内存溢出为你收集整理的用于HTML Markdown源代码的词法分析器(java)全部内容,希望文章能够帮你解决用于HTML Markdown源代码的词法分析器(java)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)