我正在编写一个编译器。我正处于第一阶段,试图将一切都标记出来。我把它全部写完了,但是我收到了一个错误。我已经阅读了三次或四次文档(smlnj),并且错误信息量不大。
我认为我必须弄乱程序的状态更改方面,它对于刚创建令牌的事情很好,但是当我使用YYBEGIN更改为状态时,它会爆炸。
这是我的lex文件:
type pos = int;
type lexresult = Tokens.token;
val lineNum = ErrorMsg.lineNum;
val linePos = ErrorMsg.linePos;
val commentDepth = ref 0;
fun incCom(cmDepth) = cmDepth := !cmDepth + 1;
fun decCom(cmDepth) = cmDepth := !cmDepth - 1;
fun err(p1,p2) = ErrorMsg.error p1;
fun eof() = let val pos = hd(!linePos) in Tokens.EOF(pos,pos) end;
%%
digits=[0-9]+;
%s COMMENT STRING;
%%
<INITIAL,COMMENT>\n => (lineNum := !lineNum+1; linePos := yypos :: !linePos; continue());
<INITIAL>"type" => (Tokens.TYPE(yypos, yypos+4));
<INITIAL>"var" => (Tokens.VAR(yypos,yypos+3));
<INITIAL>"function" => (Tokens.FUNCTION(yypos, yypos+8));
<INITIAL>"break" => (Tokens.BREAK(yypos, yypos+5));
<INITIAL>"of" => (Tokens.OF(yypos, yypos+2));
<INITIAL>"end" => (Tokens.END(yypos, yypos+3));
<INITIAL>"in" => (Tokens.IN(yypos, yypos+2));
<INITIAL>"nil" => (Tokens.NIL(yypos, yypos+3));
<INITIAL>"let" => (Tokens.LET(yypos, yypos+3));
<INITIAL>"do" => (Tokens.DO(yypos, yypos+2));
<INITIAL>"to" => (Tokens.TO(yypos, yypos+2));
<INITIAL>"for" => (Tokens.FOR(yypos, yypos+3));
<INITIAL>"while" => (Tokens.WHILE(yypos, yypos+5));
<INITIAL>"else" => (Tokens.ELSE(yypos, yypos+4));
<INITIAL>"then" => (Tokens.THEN(yypos, yypos+4));
<INITIAL>"if" => (Tokens.IF(yypos, yypos+2));
<INITIAL>"array" => (Tokens.ARRAY(yypos, yypos+5));
<INITIAL>":=" => (Tokens.ASSIGN(yypos, yypos+2));
<INITIAL>"|" => (Tokens.OR(yypos, yypos+1));
<INITIAL>"&" => (Tokens.AND(yypos, yypos+1));
<INITIAL>">=" => (Tokens.GE(yypos, yypos+2));
<INITIAL>">" => (Tokens.GT(yypos, yypos+1));
<INITIAL>"<=" => (Tokens.LE(yypos, yypos+2));
<INITIAL>"<" => (Tokens.LT(yypos, yypos+1));
<INITIAL>"<>" => (Tokens.NEQ(yypos, yypos+2));
<INITIAL>"=" => (Tokens.EQ(yypos, yypos+1));
<INITIAL>"/" => (Tokens.DIVIDE(yypos, yypos+1));
<INITIAL>"*" => (Tokens.TIMES(yypos, yypos+1));
<INITIAL>"-" => (Tokens.MINUS(yypos, yypos+1));
<INITIAL>"+" => (Tokens.PLUS(yypos, yypos+1));
<INITIAL>"." => (Tokens.DOT(yypos, yypos+1));
<INITIAL>"}" => (Tokens.RBRACE(yypos, yypos+1));
<INITIAL>"{" => (Tokens.LBRACE(yypos, yypos+1));
<INITIAL>"]" => (Tokens.RBRACK(yypos, yypos+1));
<INITIAL>"[" => (Tokens.LBRACK(yypos, yypos+1));
<INITIAL>")" => (Tokens.RPAREN(yypos, yypos+1));
<INITIAL>"(" => (Tokens.LPAREN(yypos, yypos+1));
<INITIAL>";" => (Tokens.SEMICOLON(yypos, yypos+1));
<INITIAL>":" => (Tokens.COLON(yypos, yypos+1));
<INITIAL>"," => (Tokens.COMMA(yypos,yypos+1));
<INITIAL>{digits} => (Tokens.INT(valOf(Int.fromString(yytext)), yypos, yypos + (size yytext)));
<INITIAL>[a-z][a-z0-9_]* => (Tokens.ID(yytext, yypos, yypos + (size yytext)));
<INITIAL>(").*(") => (Tokens.STRING(yytext, yypos, yypos + (size yytext)));
<INITIAL>"\"" => (YYBEGIN STRING; continue());
<STRING>"\"" => (YYBEGIN INITIAL; continue());
<INITIAL>"/*" => (incCom commentDepth; YYBEGIN COMMENT; continue());
<COMMENT>"/*" => (incCom commentDepth; continue());
<COMMENT>"*/" => (print "OTHER TRACE!\n"; decCom commentDepth; if !commentDepth <= 0 then YYBEGIN INITIAL else (); continue());
<INITIAL,COMMENT>[\ \t]+ => (print "TRACE 22222\n"; continue());
<INITIAL>. => (ErrorMsg.error yypos ("illegal character " ^ yytext); continue());
这是我正在标记的源文件:
var , 123
/* some comment */
234 "d"
它不喜欢我的评论,也不喜欢我的字符串。谢谢你的帮助。
编辑:所以这是我更新的lex文件。我已经确定了它破裂的地方。我检测到新评论的开始就好了,它很好地切换到COMMENT状态,它在评论之后检测到空间就好了,但随后它中断了,它永远不会达到它吃掉int的程度。
答案 0 :(得分:2)
评论由*/
而不是*\
终止。 (<COMMENT>"*\\" =>
)。当然,您需要<COMMENT>.
规则来处理评论本身。
我没有看到状态<STRING>
的任何词汇规则;如果没有,那将是字符串的问题。否则,我认为这与这些规则有关。
根据编辑过的问题进行编辑(不是最好用的SO,恕我直言):
我不是SML lexing的专家,但在我看来,你需要一个规则来处理评论和字符串的内容(正如我在第一段中所述) 。换句话说,当遇到终止序列以外的字符时(或者,如果是注释,则为空格),没有适用于状态<COMMENT>
或状态<STRING>
的规则。