Project Report
Project Report
Cool.flex
/*
* 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't remove anything that was here initially
*/
%{
#include <cool-parse.h>
#include <stringtab.h>
#include <utilities.h>
#include <stdint.h>
/*
* Add Your own definitions here
*/
char string_const[MAX_STR_CONST];
int string_const_len;
bool str_contain_null_char;
%}
/*
* Define names for regular expressions here.
*/
%option noyywrap
%x LINE_COMMENT BLOCK_COMMENT STRING
DARROW =>
ASSIGN <-
LE <=
%%
\n { curr_lineno++; }
[ \t\r\v\f]+ {}
/*
* Nested comments
*/
<LINE_COMMENT>. {}
<BLOCK_COMMENT>. {}
/*
* The multiple-character operators.
*/
/*
* The single-character operators.
*/
/*
* Keywords are case-insensitive except for the values true and false,
* which must begin with a lower-case letter.
*/
t[rR][uU][eE] {
cool_yylval.boolean = 1;
return (BOOL_CONST);
}
f[aA][lL][sS][eE] {
cool_yylval.boolean = 0;
return (BOOL_CONST);
}
/*
* String constants (C syntax)
* Escape sequence \c is accepted for all characters c. Except for
* \n \t \b \f, the result is c.
*
*/
\" {
memset(string_const, 0, sizeof string_const);
string_const_len = 0; str_contain_null_char = false;
BEGIN STRING;
}
<STRING><<EOF>> {
strcpy(cool_yylval.error_msg, "EOF in string constant");
BEGIN 0; return (ERROR);
}
<STRING>\\. {
if (string_const_len >= MAX_STR_CONST) {
strcpy(cool_yylval.error_msg, "String constant too long");
BEGIN 0; return (ERROR);
}
switch(yytext[1]) {
case '\"': string_const[string_const_len++] = '\"'; break;
case '\\': string_const[string_const_len++] = '\\'; break;
case 'b' : string_const[string_const_len++] = '\b'; break;
case 'f' : string_const[string_const_len++] = '\f'; break;
case 'n' : string_const[string_const_len++] = '\n'; break;
case 't' : string_const[string_const_len++] = '\t'; break;
case '0' : string_const[string_const_len++] = 0;
str_contain_null_char = true; break;
default : string_const[string_const_len++] = yytext[1];
}
}
<STRING>\\\n { curr_lineno++; }
<STRING>\n {
curr_lineno++;
strcpy(cool_yylval.error_msg, "Unterminated string constant");
BEGIN 0; return (ERROR);
}
<STRING>\" {
if (string_const_len > 1 && str_contain_null_char) {
strcpy(cool_yylval.error_msg, "String contains null character");
BEGIN 0; return (ERROR);
}
cool_yylval.symbol = stringtable.add_string(string_const);
BEGIN 0; return (STR_CONST);
}
<STRING>. {
if (string_const_len >= MAX_STR_CONST) {
strcpy(cool_yylval.error_msg, "String constant too long");
BEGIN 0; return (ERROR);
}
string_const[string_const_len++] = yytext[0];
}
/*
* Integers and identifiers.
*/
[0-9]+ {
cool_yylval.symbol = inttable.add_string(yytext);
return (INT_CONST);
}
[A-Z][A-Za-z0-9_]* {
cool_yylval.symbol = idtable.add_string(yytext);
return (TYPEID);
}
[a-z][A-Za-z0-9_]* {
cool_yylval.symbol = idtable.add_string(yytext);
return (OBJECTID);
}
/*
* Other errors.
*/
. {
strcpy(cool_yylval.error_msg, yytext);
return (ERROR);
}
%%
Solution:
Cool.y
/*
* cool.y
* Parser definition for the COOL language.
*
*/
%{
#include <iostream>
#include "cool-tree.h"
#include "stringtab.h"
#include "utilities.h"
/* Locations */
#define YYLTYPE int /* the type of locations */
#define cool_yylloc curr_lineno /* use the curr_lineno from the lexer
for the location of tokens */
#define SET_NODELOC(Current) \
node_lineno = Current;
*/
void yyerror(char *s); /* defined below; called for each parse error */
extern int yylex(); /* the entry point to the lexer */
/***************************************************************
*********/
/* DONT CHANGE ANYTHING IN THIS SECTION */
/* A union of all the types that can be the result of parsing actions. */
%union {
Boolean boolean;
Symbol symbol;
Program program;
Class_ class_;
Classes classes;
Feature feature;
Features features;
Formal formal;
Formals formals;
Case case_;
Cases cases;
Expression expression;
Expressions expressions;
char *error_msg;
}
/*
Declare the terminals; a few have types for associated lexemes.
The token ERROR is never used in the parser; thus, it is a parse
error when the lexer returns it.
/***************************************************************
***********/
/* Complete the nonterminal list below, giving a type for the semantic
value of each non terminal. (See section 3.6 in the bison
documentation for details). */
feature_list: feature
{ $$ = single_Features($1); }
| feature_list feature
{ $$ = append_Features($1, single_Features($2)); }
;
dummy_formal_list: /* empty */
{ $$ = nil_Formals(); }
;
formal_list: formal
{ $$ = single_Formals($1); }
| formal_list ',' formal
{ $$ = append_Formals($1, single_Formals($3)); }
;
expression : OBJECTID
{ @$ = @1; $$ = object($1); }
| STR_CONST
{ @$ = @1; $$ = string_const($1); }
| INT_CONST
{ @$ = @1; $$ = int_const($1); }
| BOOL_CONST
{ @$ = @1; $$ = bool_const($1); }
| NOT expression
{ @$ = @1; $$ = comp($2); }
| '~' expression
{ @$ = @1; $$ = neg($2); }
| expression '+' expression
{ @$ = @1; $$ = plus($1, $3); }
| expression '-' expression
{ @$ = @1; $$ = sub($1, $3); }
| expression '*' expression
{ @$ = @1; $$ = mul($1, $3); }
| expression '/' expression
{ @$ = @1; $$ = divide($1, $3); }
| expression LE expression
{ @$ = @1; $$ = leq($1, $3); }
| expression '<' expression
{ @$ = @1; $$ = lt($1, $3); }
| expression '=' expression
{ @$ = @1; $$ = eq($1, $3); }
| OBJECTID ASSIGN expression
{ @$ = @1; $$ = assign($1, $3); }
| NEW TYPEID
{ @$ = @1; $$ = new_($2); }
| ISVOID expression
{ @$ = @1; $$ = isvoid($2); }
| '(' expression ')'
{ @$ = @1; $$ = $2; }
| '{' expression_block_list '}'
{ @$ = @1; $$ = block($2); }
| OBJECTID '(' expression_list ')'
{ @$ = @1; $$ = dispatch(object(idtable.add_string("self")), $1, $3); }
| expression '.' OBJECTID '(' expression_list ')'
{ @$ = @1; $$ = dispatch($1, $3, $5); }
| expression '@' TYPEID '.' OBJECTID '(' expression_list ')'
{ @$ = @1; $$ = static_dispatch($1, $3, $5, $7); }
| OBJECTID '(' expression_dummy_list ')'
{ @$ = @1; $$ = dispatch(object(idtable.add_string("self")), $1, $3); }
| expression '.' OBJECTID '(' expression_dummy_list ')'
{ @$ = @1; $$ = dispatch($1, $3, $5); }
| expression '@' TYPEID '.' OBJECTID '(' expression_dummy_list ')'
{ @$ = @1; $$ = static_dispatch($1, $3, $5, $7); }
| IF expression THEN expression ELSE expression FI
{ @$ = @1; $$ = cond($2, $4, $6); }
| WHILE expression LOOP expression POOL
{ @$ = @1; $$ = loop($2, $4); }
| CASE expression OF case_list ESAC
{ @$ = @1; $$ = typcase($2, $4); }
| LET let
{ @$ = @1;$$ = $2; }
;
expression_dummy_list: /* empty */
{ $$ = nil_Expressions(); }
;
expression_list: expression
{ $$ = single_Expressions($1); }
| expression_list ',' expression
{ $$ = append_Expressions($1, single_Expressions($3)); }
;
/* end of grammar */
%%
cerr << "\"" << curr_filename << "\", line " << curr_lineno << ": " \
<< s << " at or near ";
print_cool_token(yychar);
cerr << endl;
omerrs++;