如何区分在 Lexer 中具有相似模式但在解析器中出现在不同上下文中的标记
how to distinguish tokens which have similar patterns in Lexer, but they occur in different contexts in the parser
我在 Lexer.x 中有两个非常相似的模式,第一个是数字,第二个是字节。他们来了。
$digit=0-9
$byte=[a-f0-9]
$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+e$digit+ { \s -> TNum (readRational s) }
$digit+e$digit+ { \s -> TNum (readRational s) }
$byte$byte { \s -> TByte (encodeUtf8(pack s)) }
我有Parser.y
%token
cnst { TNum $$}
byte { TByte $$}
'[' { TOSB }
']' { TCSB }
%%
Expr:
'[' byte ']' {}
| const {}
当我写的时候,我得到了。
[ 11 ] parse error
11 ok
但是当我在 Lexer 中将字节模式放在数字之前时
$digit=0-9
$byte=[a-f0-9]
$byte$byte { \s -> TByte (encodeUtf8(pack s)) }
$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+e$digit+ { \s -> TNum (readRational s) }
$digit+e$digit+ { \s -> TNum (readRational s) }
我得到了
[ 11 ] ok
11 parse error
我认为发生这种情况是因为 Lexer 从字符串中生成标记,然后将它们提供给解析器。
当解析器等待字节令牌时,它得到了数字令牌,解析器没有机会从这个值中生成另一个令牌。
这种情况我该怎么办?
在这种情况下,您应该推迟解析。例如,您可以制作一个 TNumByte
数据构造函数,将值存储为 String
:
Token
= TByte ByteString
| TNum Rational
| TNumByte String
-- …
对于一个$digit
的序列,目前还不清楚是要把这个解释成byte还是number,所以我们为此构造一个TNumByte
:
$digit=0-9
$byte=[a-f0-9]
<strong>$digit$digit</strong> { <strong>TNumByte</strong> }
$byte$byte { \s -> TByte (encodeUtf8(pack s)) }
$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+e$digit+ { \s -> TNum (readRational s) }
$digit+e$digit+ { \s -> TNum (readRational s) }
然后在解析器中我们可以根据上下文来决定:
%token
cnst { TNum $$ }
byte { TByte $$ }
numbyte { TNumByte $$ } -- 🖘 can be int or byte
'[' { TOSB }
']' { TCSB }
%%
Expr
: '[' byte ']' { }
| '[' numbyte ']' { encodeUtf8(pack ) } -- 🖘 interpret as byte
| const { }
| numbyte { readRational } -- 🖘 interpret as int
;
我在 Lexer.x 中有两个非常相似的模式,第一个是数字,第二个是字节。他们来了。
$digit=0-9
$byte=[a-f0-9]
$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+e$digit+ { \s -> TNum (readRational s) }
$digit+e$digit+ { \s -> TNum (readRational s) }
$byte$byte { \s -> TByte (encodeUtf8(pack s)) }
我有Parser.y
%token
cnst { TNum $$}
byte { TByte $$}
'[' { TOSB }
']' { TCSB }
%%
Expr:
'[' byte ']' {}
| const {}
当我写的时候,我得到了。
[ 11 ] parse error
11 ok
但是当我在 Lexer 中将字节模式放在数字之前时
$digit=0-9
$byte=[a-f0-9]
$byte$byte { \s -> TByte (encodeUtf8(pack s)) }
$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+e$digit+ { \s -> TNum (readRational s) }
$digit+e$digit+ { \s -> TNum (readRational s) }
我得到了
[ 11 ] ok
11 parse error
我认为发生这种情况是因为 Lexer 从字符串中生成标记,然后将它们提供给解析器。 当解析器等待字节令牌时,它得到了数字令牌,解析器没有机会从这个值中生成另一个令牌。 这种情况我该怎么办?
在这种情况下,您应该推迟解析。例如,您可以制作一个 TNumByte
数据构造函数,将值存储为 String
:
Token
= TByte ByteString
| TNum Rational
| TNumByte String
-- …
对于一个$digit
的序列,目前还不清楚是要把这个解释成byte还是number,所以我们为此构造一个TNumByte
:
$digit=0-9
$byte=[a-f0-9]
<strong>$digit$digit</strong> { <strong>TNumByte</strong> }
$byte$byte { \s -> TByte (encodeUtf8(pack s)) }
$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+ { \s -> TNum (readRational s) }
$digit+.$digit+e$digit+ { \s -> TNum (readRational s) }
$digit+e$digit+ { \s -> TNum (readRational s) }
然后在解析器中我们可以根据上下文来决定:
%token
cnst { TNum $$ }
byte { TByte $$ }
numbyte { TNumByte $$ } -- 🖘 can be int or byte
'[' { TOSB }
']' { TCSB }
%%
Expr
: '[' byte ']' { }
| '[' numbyte ']' { encodeUtf8(pack ) } -- 🖘 interpret as byte
| const { }
| numbyte { readRational } -- 🖘 interpret as int
;