/* * The scanner definition for COOL. */ %{ #include #include #include /* The compiler assumes these identifiers. */ #define yylval cool_yylval #define yylex cool_yylex /* Max size of string constants */ #define MAX_STR_CONST 1025 #define YY_NO_UNPUT /* keep g++ happy */ extern FILE *fin; /* we read from this file */ /* define YY_INPUT so we read from the FILE fin: * This change makes it possible to use this scanner in * the Cool compiler. */ #undef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( (result = fread( (char*)buf, sizeof(char), max_size, fin)) < 0) \ YY_FATAL_ERROR( "read() in flex scanner failed"); char string_buf[MAX_STR_CONST]; /* to assemble string constants */ char *string_buf_ptr; extern int curr_lineno; extern int verbose_flag; extern YYSTYPE cool_yylval; /* * Add Your own definitions here */ char* escapeString(const char* str) { unsigned length = 0; for (const char* i = str; *i != '\0'; ++i) { if (*i == '\\') ++i; if (*i == '\n') curr_lineno++; // this maybe shouldn't be here, but it's fine length++; } char* out = new char[length - 1]; out[length - 2] = '\0'; char* currout = out; for (const char* i = str + 1; i[1] != '\0'; ++i) { if (*i != '\\') *(currout++) = *i; else switch (i[1]) { case 'b': *(currout++) = '\b'; ++i; break; case 't': *(currout++) = '\t'; ++i; break; case 'n': *(currout++) = '\n'; ++i; break; case 'f': *(currout++) = '\f'; ++i; break; case '\\': *(currout++) = '\\'; ++i; break; } } return out; } bool strStarted = false; unsigned openedComments = 0; %} /* * Info from /usr/class/cs143/cool/include/PA2/cool-parse.h * Tokens: * STR_CONST CLASS ELSE FI IF IN INHERITS ISVOID LET LOOP POOL THEN WHILE CASE ESAC NEW OF NOT DARROW TYPEID OBJECTID INT_CONST BOOL_CONST ASSIGN LE ERROR * yylval types: * Boolean boolean; * Symbol symbol; * char *error_msg; */ ALL (.|\n) ENDL \n|\r\n BLANK [ \f\t\v\r] IDCHR [A-Za-z0-9_] %x MULTILINE %% --[^\n\r]* { } \(\* { openedComments++; BEGIN(MULTILINE); } \*\) { if (--openedComments == 0) BEGIN(INITIAL); } {ENDL} { curr_lineno++; } . { } <> { cool_yylval.error_msg = "EOF in comment"; BEGIN(INITIAL); return (ERROR); } \"([^"\0\n\\]|\\[^\0])*\" { char* str = escapeString(yytext); if (strlen(str) >= MAX_STR_CONST) { cool_yylval.error_msg = "String constant too long"; return (ERROR); } else { cool_yylval.symbol = inttable.add_string(str); return (STR_CONST); } } \"([^"\0\n\\]|\\[^\0])*{ENDL} { cool_yylval.error_msg = "Unterminated string constant"; curr_lineno++; return (ERROR); } \"([^"\0\n\\]|\\{ALL})*(\"|{ENDL}) { cool_yylval.error_msg = "String contains escaped null character."; return (ERROR); } \"([^"\n\\]|\\[^\0])*(\"|{ENDL}) { cool_yylval.error_msg = "String contains null character."; return (ERROR); } \"([^"\0\n\\]|\\[^\0])* { cool_yylval.error_msg = "EOF in string constant"; return (ERROR); } \*\) { cool_yylval.error_msg = "Unmatched *)"; return (ERROR); } (?i:class) { return (CLASS); } (?i:else) { return (ELSE); } (?i:fi) { return (FI); } (?i:if) { return (IF); } (?i:in) { return (IN); } (?i:inherits) { return (INHERITS); } (?i:isvoid) { return (ISVOID); } (?i:let) { return (LET); } (?i:loop) { return (LOOP); } (?i:pool) { return (POOL); } (?i:then) { return (THEN); } (?i:while) { return (WHILE); } (?i:case) { return (CASE); } (?i:esac) { return (ESAC); } (?i:new) { return (NEW); } (?i:of) { return (OF); } (?i:not) { return (NOT); } "=>" { return (DARROW); } "<=" { return (LE); } "<-" { return (ASSIGN); } (t(?i:rue)|f(?i:alse)) { cool_yylval.boolean = *yytext == 't'; return (BOOL_CONST); } [a-z]{IDCHR}* { cool_yylval.symbol = inttable.add_string(yytext); return (OBJECTID); } [0-9]+ { cool_yylval.symbol = inttable.add_string(yytext); return (INT_CONST); } [A-Z]{IDCHR}* { cool_yylval.symbol = inttable.add_string(yytext); return (TYPEID); } \{|\}|\(|\)|:|;|,|@|\.|\+|-|\*|\/|~|<|<=|= { return *yytext; } {ENDL} { curr_lineno++; } {BLANK} { } . { cool_yylval.error_msg = yytext; return (ERROR); } %%