如何在Racket中识别并标记gosub语句后的行号令牌
解决Racket parser-tools/lex中gosub后数字识别为LINE-NUM的问题
问题核心
你需要让词法分析器区分普通数字和gosub语句后的行号数字,当前存在的问题:
- 词法分析器无状态,无法识别"gosub"上下文
line-num正则定义错误(仅匹配单个1-9数字)- 关键字规则错误使用
(:+),会匹配重复关键字(如"readread") - 普通数字规则优先级高于行号规则,导致gosub后的数字被识别为NUMBER
修改方案
利用parser-tools/lex的状态机功能,在识别到gosub后切换到专属状态,将后续数字识别为LINE-NUM,完成后切回初始状态,同时修正正则和规则优先级。
1. 修正正则缩写定义
调整define-lex-abbrevs,修复行号和关键字的正则匹配:
(define-lex-abbrevs [read "read"] [write "write"] [goto "goto"] [gosub "gosub"] [line-num (:+ digit)] ; 匹配一个或多个数字作为行号 [letter (:or (:/ "a" "z") (:/ #\A #\Z) "?" "!")] [digit (:/ #\0 #\9)] [mult-op (or "*" "/")] [add-op (or "+" "-")] [end-of-file "$$"] [paren-start "("] [paren-end ")"] )
2. 带状态的词法分析器实现
通过状态切换实现上下文感知,完整修改后的lexer代码:
(define lex (lexer-src-pos ;; 所有状态通用规则 [(eof) 'EOF] [(:+ end-of-file) (token-END-OF-PROGRAM (string->symbol lexeme))] [(:or #\tab #\space #\newline) (return-without-pos (lex input-port))] ["\r"] (token-newline) [(:or ":" ":=" "^" "<" ">" "=")] (string->symbol lexeme) [(:or "+" "-")] (token-ADD-OP (string->symbol lexeme)) [(:or "*" "/")] (token-MULT-OP (string->symbol lexeme)) [read] (token-READ lexeme) [write] (token-WRITE lexeme) [goto] (token-GOTO lexeme) ;; 初始状态规则 [INITIAL [gosub (begin (token-GOSUB lexeme) (lexer-set-state! 'AFTER-GOSUB) ; 切换到gosub后状态 (return-without-pos (lex input-port)))] [(:+ digit) (token-NUMBER (string->number lexeme))] [(:+ letter) (token-IDENTIFIER lexeme)] [(:+ paren-start) (token-PAREN-START lexeme)] [(:+ paren-end) (token-PAREN-END lexeme)]] ;; gosub后的专属状态规则 [AFTER-GOSUB [line-num (begin (token-LINE-NUM (string->number lexeme)) ; 行号转数值类型 (lexer-set-state! 'INITIAL) ; 切回初始状态 (return-without-pos (lex input-port)))] ;; 若遇到非数字,切回初始状态重新扫描 [any-char (begin (lexer-set-state! 'INITIAL) (return-without-pos (lex input-port)))]] ))
3. 效果验证
对于输入片段30 gosub 400,会输出:
token-GOSUB: "gosub"token-line-num: 400
而普通数字(如40 if C = 400 then write C中的400)仍会被识别为NUMBER令牌,满足需求。
关键说明
- 状态机作用:通过切换状态让分析器感知上下文,区分不同场景的数字
- 规则优先级:
parser-tools/lex按规则顺序匹配最长前缀,需将上下文相关规则放在普通规则之前 - 数值转换:将LINE-NUM的字符串转为数值类型,方便后续语法分析使用
内容的提问来源于stack exchange,提问作者Flurrshify
相关产品推荐
相关产品推荐

