Попытка понять синтаксис Lex для стандартного ML (ml-lex)

Пишу компилятор. Я на первом этапе, пытаюсь все токенизировать. Я все написал, но у меня ошибка. Я читал документы (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"

Ему не нравятся мои комментарии и мои строки. Спасибо за помощь.

EDIT: Вот мой обновленный файл lex. Я точно определил, где он ломается. Я прекрасно определяю начало нового комментария, он отлично переключается в состояние COMMENT, он прекрасно обнаруживает пробел после комментария, но затем он ломается, он никогда не доходит до точки, где он съедает int.


person robins35    schedule 10.04.2014    source источник


Ответы (1)


Комментарии заканчиваются */, а не *\. (<COMMENT>"*\\" =>). И, конечно же, вам нужно правило <COMMENT>. для обработки самого комментария.

Я не вижу никакого лексического правила для состояния <STRING>; если его нет, то это будет проблема со строками. В противном случае, я думаю, это как-то связано с этими правилами.

Редактировать на основе отредактированного вопроса (не лучшее использование SO, ИМХО):

Я не специалист по лексике SML, но мне кажется, что вам понадобится правило для работы с содержимым комментариев и строк (как я сказал выше в первом абзаце). Другими словами, нет правила, которое будет применяться в состоянии <COMMENT> или состоянии <STRING>, когда встречается символ, отличный от завершающей последовательности (или, в случае комментариев, пробел).

person rici    schedule 10.04.2014