设计语言词法分析器
Designing a Language Lexer
我目前正在创建一种编程语言。我已经布置了我的整个设计,并且正在为它创建 Lexer。过去我创建了许多词法分析器和词法分析器生成器,但从未采用 "standard",如果存在的话。
是否应该创建词法分析器以最大限度地提高与尽可能多的解析器一起使用的能力?
因为我的设计方式,它们看起来像下面这样:
代码:
int main() {
printf("Hello, World!");
}
词法分析器:
[
KEYWORD:INT, IDENTIFIER:"main", LEFT_ROUND_BRACKET, RIGHT_ROUNDBRACKET, LEFT_CURLY_BRACKET,
IDENTIFIER:"printf", LEFT_ROUND_BRACKET, STRING:"Hello, World!", RIGHT_ROUND_BRACKET, COLON,
RIGHT_CURLY_BRACKET
]
Lexer 应该采用这种方式吗? 另请注意,在创建 Lexer 之后我的下一步应该做什么?我真的不想使用 ANTLR 或 Lex+Yacc 或 Flex+Bison 等东西.我是从零开始做的。
如果您不想使用解析器生成器[注 1],那么词法分析器如何向解析器提供信息完全取决于您。
即使您确实使用解析器生成器,也有许多细节将取决于项目。有时,词法分析器用每个标记 调用 解析器会很方便;如果解析器调用词法分析器,其他时候会更容易;在某些情况下,您会希望有一个与每个组件单独交互的驱动程序。显然,您的令牌的精确数据类型因项目而异,这也会对您的沟通方式产生影响。
就个人而言,我会避免使用全局变量(如在原始 yacc/lex 协议中那样),但这是一个普遍的风格问题。
大多数词法分析器以流模式工作,而不是对整个输入进行分词,然后将分词向量传递给更高的幂。一次标记一个标记有很多优点,特别是如果标记化是上下文相关的,而且,让我们面对现实吧,几乎所有语言的语法中都有一些不纯某处。但是,同样,这完全取决于您。
祝你项目顺利。
备注:
- 您是否也放弃使用编译器并使用汇编程序甚至二进制从头开始编写所有代码?
Is there a specific way a lexer should be created to maximise capability to use it with as many parsers as possible?
在我看过的词法分析器中,规范的 API 非常少。基本上是:
Token readNextToken();
词法分析器维护对源文本的引用及其当前查找位置的内部指针。然后,每次调用它时,它都会扫描并 returns 下一个标记。
Token类型通常有:
- 一个"type"枚举它是哪种令牌:字符串,运算符,标识符等。通常有特殊类型的"EOF",意思是在输入的结尾,"ERROR" 用于语法错误来自词法语法的罕见情况。这主要是源中未终止的字符串文字或完全未知的字符。
- 令牌的源文本。
- 有时,文字会在词法分析期间转换为其正确的值表示形式,在这种情况下,您也会拥有该值。因此,数字标记将具有“123”作为 text,但也具有数字 value 123。或者您可以在 parsing/compilation 期间执行此操作.
- 令牌在源文件中的位置。这是为了错误报告。通常是基于 1 的行和列,但也可以只是开始和结束字节偏移量。后者的生成速度稍快一些,如果需要可以延迟转换为行和列。
根据您的语法,您可能还需要能够倒带词法分析器。
我目前正在创建一种编程语言。我已经布置了我的整个设计,并且正在为它创建 Lexer。过去我创建了许多词法分析器和词法分析器生成器,但从未采用 "standard",如果存在的话。
是否应该创建词法分析器以最大限度地提高与尽可能多的解析器一起使用的能力?
因为我的设计方式,它们看起来像下面这样:
代码:
int main() {
printf("Hello, World!");
}
词法分析器:
[
KEYWORD:INT, IDENTIFIER:"main", LEFT_ROUND_BRACKET, RIGHT_ROUNDBRACKET, LEFT_CURLY_BRACKET,
IDENTIFIER:"printf", LEFT_ROUND_BRACKET, STRING:"Hello, World!", RIGHT_ROUND_BRACKET, COLON,
RIGHT_CURLY_BRACKET
]
Lexer 应该采用这种方式吗? 另请注意,在创建 Lexer 之后我的下一步应该做什么?我真的不想使用 ANTLR 或 Lex+Yacc 或 Flex+Bison 等东西.我是从零开始做的。
如果您不想使用解析器生成器[注 1],那么词法分析器如何向解析器提供信息完全取决于您。
即使您确实使用解析器生成器,也有许多细节将取决于项目。有时,词法分析器用每个标记 调用 解析器会很方便;如果解析器调用词法分析器,其他时候会更容易;在某些情况下,您会希望有一个与每个组件单独交互的驱动程序。显然,您的令牌的精确数据类型因项目而异,这也会对您的沟通方式产生影响。
就个人而言,我会避免使用全局变量(如在原始 yacc/lex 协议中那样),但这是一个普遍的风格问题。
大多数词法分析器以流模式工作,而不是对整个输入进行分词,然后将分词向量传递给更高的幂。一次标记一个标记有很多优点,特别是如果标记化是上下文相关的,而且,让我们面对现实吧,几乎所有语言的语法中都有一些不纯某处。但是,同样,这完全取决于您。
祝你项目顺利。
备注:
- 您是否也放弃使用编译器并使用汇编程序甚至二进制从头开始编写所有代码?
Is there a specific way a lexer should be created to maximise capability to use it with as many parsers as possible?
在我看过的词法分析器中,规范的 API 非常少。基本上是:
Token readNextToken();
词法分析器维护对源文本的引用及其当前查找位置的内部指针。然后,每次调用它时,它都会扫描并 returns 下一个标记。
Token类型通常有:
- 一个"type"枚举它是哪种令牌:字符串,运算符,标识符等。通常有特殊类型的"EOF",意思是在输入的结尾,"ERROR" 用于语法错误来自词法语法的罕见情况。这主要是源中未终止的字符串文字或完全未知的字符。
- 令牌的源文本。
- 有时,文字会在词法分析期间转换为其正确的值表示形式,在这种情况下,您也会拥有该值。因此,数字标记将具有“123”作为 text,但也具有数字 value 123。或者您可以在 parsing/compilation 期间执行此操作.
- 令牌在源文件中的位置。这是为了错误报告。通常是基于 1 的行和列,但也可以只是开始和结束字节偏移量。后者的生成速度稍快一些,如果需要可以延迟转换为行和列。
根据您的语法,您可能还需要能够倒带词法分析器。