[英]Context-Free Grammar for Custom Programming Language
在我的大學完成了編譯器設計課程之后,我一直在為一種簡單的編程語言制作編譯器,但是我在解析器方面遇到了麻煩。 我在mosml中制作編譯器,並使用其內置的解析器mosmlyac構造解析器。 這是我的解析器的摘錄,其中顯示了語法和關聯性+優先級。
...
%right ASSIGN
%left OR
%left AND
%nonassoc NOT
%left EQUAL LESS
%left PLUS MINUS
%left TIMES DIVIDE
%nonassoc NEGATE
...
Prog : FunDecs EOF { $1 }
;
FunDecs : Fun FunDecs { $1 :: $2 }
| { [] }
;
Fun : Type ID LPAR TypeIds RPAR StmtBlock { FunDec (#1 $2, $1, $4, $6, #2 $2) }
| Type ID LPAR RPAR StmtBlock { FunDec (#1 $2, $1, [], $5, #2 $2) }
;
TypeIds : Type ID COMMA TypeIds { Param (#1 $2, $1) :: $4 }
| Type ID { [Param (#1 $2, $1)] }
;
Type : VOID { Void }
| INT { Int }
| BOOL { Bool }
| CHAR { Char }
| STRING { Array (Char) }
| Type LBRACKET RBRACKET { Array ($1) }
;
StmtBlock : LCURLY StmtList RCURLY { $2 }
;
StmtList : Stmt StmtList { $1 :: $2 }
| { [] }
;
Stmt : Exp SEMICOLON { $1 }
| IF Exp StmtBlock { IfElse ($2, $3, [], $1) }
| IF Exp StmtBlock ELSE StmtBlock { IfElse ($2, $3, $5, $1) }
| WHILE Exp StmtBlock { While ($2, $3, $1) }
| RETURN Exp SEMICOLON { Return ($2, (), $1) }
;
Exps : Exp COMMA Exps { $1 :: $3 }
| Exp { [$1] }
;
Index : LBRACKET Exp RBRACKET Index { $2 :: $4 }
| { [] }
;
Exp : INTLIT { Constant (IntVal (#1 $1), #2 $1) }
| TRUE { Constant (BoolVal (true), $1) }
| FALSE { Constant (BoolVal (false), $1) }
| CHRLIT { Constant (CharVal (#1 $1), #2 $1) }
| STRLIT { StringLit (#1 $1, #2 $1) }
| LCURLY Exps RCURLY { ArrayLit ($2, (), $1) }
| ARRAY LPAR Exp RPAR { ArrayConst ($3, (), $1) }
| Exp PLUS Exp { Plus ($1, $3, $2) }
| Exp MINUS Exp { Minus ($1, $3, $2) }
| Exp TIMES Exp { Times ($1, $3, $2) }
| Exp DIVIDE Exp { Divide ($1, $3, $2) }
| NEGATE Exp { Negate ($2, $1) }
| Exp AND Exp { And ($1, $3, $2) }
| Exp OR Exp { Or ($1, $3, $2) }
| NOT Exp { Not ($2, $1) }
| Exp EQUAL Exp { Equal ($1, $3, $2) }
| Exp LESS Exp { Less ($1, $3, $2) }
| ID { Var ($1) }
| ID ASSIGN Exp { Assign (#1 $1, $3, (), #2 $1) }
| ID LPAR Exps RPAR { Apply (#1 $1, $3, #2 $1) }
| ID LPAR RPAR { Apply (#1 $1, [], #2 $1) }
| ID Index { Index (#1 $1, $2, (), #2 $1) }
| ID Index ASSIGN Exp { AssignIndex (#1 $1, $2, $4, (), #2 $1) }
| PRINT LPAR Exp RPAR { Print ($3, (), $1) }
| READ LPAR Type RPAR { Read ($3, $1) }
| LPAR Exp RPAR { $2 }
;
Prog是%start
符號,我故意省略了%token
和%type
聲明。
我的問題是該語法似乎模棱兩可,並且查看該語法上運行mosmlyac -v
的輸出,似乎是包含令牌ID的規則才是問題所在,並產生了shift / reduce和reduce / reduce沖突。 輸出還告訴我,規則Exp:ID永遠不會減少。
誰能幫助我使這個語法明確?
Index
有一個空的生產。
現在考慮:
Exp : ID
| ID Index
哪些適用? 由於允許Index
為空,因此沒有上下文僅適用其中之一。 您正在使用的解析器生成器顯然傾向於減少空的INDEX
,從而使Exp : ID
不可用,並產生大量沖突。
我建議將Index
更改為:
Index : LBRACKET Exp RBRACKET Index { $2 :: $4 }
| LBRACKET Exp RBRACKET { [ $2 ] }
盡管從長遠來看,使用更傳統的“左值/右值”語法可能會更好,其中lvalue
包括ID
和lvalue [ Exp ]
, rvalue
包括lvalue
。 (這將為ID [ Exp ] [ Exp ]
提供更復雜的解析樹,但是存在明顯的同態。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.