/*
* The scanner definition for COOL.
*/
/*
* Stuff enclosed in %{ %} in the first section is copied verbatim to the
* output, so headers and global definitions are placed here to be visible
* to the code in the file. Don not remove anything that was here initially
*/
%{
#include <cool-parse.h>
#include <stringtab.h>
#include <utilities.h>
/* 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");
/* to assemble string constants */
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
extern int curr_lineno;
extern int verbose_flag;
extern YYSTYPE cool_yylval;
/*
* Add Your own definitions here
*/
/* Judge whether brackets match*/
int comment_depth = 0;
int string_len;
void setErrMsg(char* msg);
bool strTooLong();
int max_strlen_err();
%}
/* Activity status */
%x COMMENT
%x S_LINE_COMMENT
%x STRING
/* Define names for regular expressions here.*/
/**/
WHITESPACE [\\ \\f\\r\\t\\v]
NUM [0-9]
ALPHANUMERIC [a-zA-Z0-9]
/* Starts with an uppercase character */
TYPE [A-Z]{ALPHANUMERIC}*
/* Starts with a lowercase character*/
OBJECTID [a-z]{ALPHANUMERIC}*
DARROW =>
LE <=
ASSIGN <-
/* Match string */
CLASS (?i:class)
ELSE (?i:else)
FI (?i:fi)
IF (?i:if)
IN (?i:in)
INHERITS (?i:inherits)
LET (?i:let)
LOOP (?i:loop)
POOL (?i:pool)
THEN (?i:then)
WHILE (?i:while)
CASE (?i:case)
NEW (?i:new)
ISVOID (?i:isvoid)
OF (?i:of)
NOT (?i:not)
INT_CONST {NUM}+
%%
/* the Comments
* -------------------------------------*/
/* eat "(" COMMENT start */
"(*" {
comment_depth++;
BEGIN(COMMENT);
}
/* continue eat "(*" comment_depth ++*/
<COMMENT>"(*" {
comment_depth++;
}
/* if comment do nothing */
<COMMENT>. {}
/* if \\n the line ++*/
<COMMENT>\\n { curr_lineno++;}
/* if not recvived */
<COMMENT><<EOF>> {
setErrMsg("EOF in comment");
BEGIN(0);
return ERROR;
}
/* if start recv is "*)" it's wrong */
"*)" {
setErrMsg("Unmatched *)");
BEGIN(0);
return ERROR;
}
/* cool notes */
"--" { BEGIN(S_LINE_COMMENT); }
<S_LINE_COMMENT>. {}
<S_LINE_COMMENT>\\n {
curr_lineno++;
BEGIN(0);
}
"false" {
cool_yylval.boolean=false;
return BOOL_CONST;
}
"true" {
cool_yylval.boolean = true;
return BOOL_CONST;
}
/* if is white space do nothing */
{WHITESPACE} {}
/* The multiple-character operators.*/
{NUM} {
cool_yylval.symbol = inttable.add_string(yytext);
return INT_CONST;
}
"=>" { return DARROW; }
"=<" { return LE; }
"<-" { return ASSIGN; }
"<" { return '<'; }
"@" { return '@'; }
"~" { return '~'; }
"=" { return '='; }
"." { return '.'; }
"-" { return '-'; }
"," { return ','; }
"+" { return '+'; }
"*" { return '*'; }
"/" { return '/'; }
"}" { return '}'; }
"{" { return '{'; }
")" { return ')'; }
"(" { return '('; }
":" { return ':'; }
";" { return ';'; }
/* keyword */
{CLASS} { return CLASS; }
{ELSE} { return ELSE; }
{FI} { return FI; }
{IF} { return IF; }
{IN} { return IN; }
{INHERITS} { return INHERITS; }
{LET} { return LET; }
{LOOP} { return LOOP; }
{POOL} { return POOL; }
{THEN} { return THEN; }
{WHILE} { return WHILE; }
{CASE} { return CASE; }
{NEW} { return NEW; }
{OF} { return OF; }
{NOT} { return NOT; }
{ISVOID} { return ISVOID; }
{TTYPE} {
cool_yylval.symbol = stringtable.add_string(yytext);
}
{OBJECTID} {
cool_yylval.symbol = stringtable.add_string(yytext);
}
/* if recv \\" , string is strat */
\\" {
BEGIN(STRING);
string_len = 0;
}
<STRING>\\" {
cool_yylval.symbol = stringtable.add_string(string_buf);
string_buf[0] = '\\0';
BEGIN(0);
return (STR_CONST);
}
<STRING><<EOF>> {
cool_yylval.error_msg = "EOF in string constant";
return ERROR;
}
<STRING>\\0 {
setErrMsg("String contains null character");
string_buf[0] = '\\0';
return ERROR;
}
<STRING>\\n {
setErrMsg("Unterminated string constant.");
string_buf[0] = '\\0';
curr_lineno++;
BEGIN(0);
return ERROR;
}
<STRING>\\\\\\n {
if(strTooLong()) return max_strlen_err();
curr_lineno++;
string_len++;
strcat(string_buf, '\\n');
}
<STRING>\\\\t {
if (strTooLong()) { return max_strlen_err(); }
string_len++;
strcat(string_buf, '\\t');
}
<STRING>\\\\b {
if (strTooLong()) { return max_strlen_err(); }
string_len++;
strcat(string_buf, '\\b');
}
<STRING>\\\\f {
if (strTooLong()) { return max_strlen_err(); }
string_len++;
strcat(string_buf, '\\f');
}
<STRING>. {
if (strTooLong()) { return max_strlen_err(); }
string_len++;
strcat(string_buf, yytext);
}
%%
void setErrMsg(char* msg) {
cool_yylval.error_msg = msg;
}int max_strlen_err() {
BEGIN(INITIAL);
cool_yylval.error_msg = "String constant too long";
return ERROR;
}
bool strTooLong() {
if (string_len + 1 >= MAX_STR_CONST) {
BEGIN(STRING_ERR);
return true;
}
return false;
}
int max_strlen_err() {
BEGIN(INITIAL);
cool_yylval.error_msg = "String constant too long";
return ERROR;
}