v4 preprocessor/macro: added various checks and error messages
git-svn-id: https://www.dynare.org/svn/dynare/dynare_v4@1719 ac1d8469-bf42-47a9-8791-bf33cf982152issue#70
parent
d70a6a812f
commit
ceee9628ed
|
@ -63,6 +63,16 @@ class MacroDriver;
|
|||
* current lexer object of the driver context. */
|
||||
#undef yylex
|
||||
#define yylex driver.lexer->lex
|
||||
|
||||
#define TYPERR_CATCH(st, loc) try \
|
||||
{ \
|
||||
st; \
|
||||
} \
|
||||
catch(MacroValue::TypeError &e) \
|
||||
{ \
|
||||
driver.error(loc, e.message); \
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%token DEFINE LINE
|
||||
|
@ -96,7 +106,7 @@ statement_list : statement EOL
|
|||
statement : expr
|
||||
{ *driver.out_stream << $1->toString(); delete $1; }
|
||||
| DEFINE NAME EQUAL expr
|
||||
{ driver.env[*$2] = $4; delete $2; }
|
||||
{ driver.set_variable(*$2, $4); delete $2; }
|
||||
| LINE STRING INTEGER
|
||||
/* Ignore @line declarations */
|
||||
|
||||
|
@ -105,51 +115,64 @@ expr : INTEGER
|
|||
| STRING
|
||||
{ $$ = new StringMV(*$1); delete $1; }
|
||||
| NAME
|
||||
{ $$ = driver.env[*$1]->clone(); delete $1; }
|
||||
{ try
|
||||
{
|
||||
$$ = driver.get_variable(*$1);
|
||||
}
|
||||
catch(MacroDriver::UnknownVariable(&e))
|
||||
{
|
||||
error(@$, "Unknown variable: " + e.name);
|
||||
}
|
||||
delete $1; }
|
||||
| LPAREN expr RPAREN
|
||||
{ $$ = $2; }
|
||||
| expr PLUS expr
|
||||
{ $$ = *$1 + *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 + *$3, @$); delete $1; delete $3; }
|
||||
| expr MINUS expr
|
||||
{ $$ = *$1 - *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 - *$3, @$); delete $1; delete $3; }
|
||||
| expr TIMES expr
|
||||
{ $$ = *$1 * *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 * *$3, @$); delete $1; delete $3; }
|
||||
| expr DIVIDE expr
|
||||
{ $$ = *$1 / *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 / *$3, @$); delete $1; delete $3; }
|
||||
| expr LESS expr
|
||||
{ $$ = *$1 < *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 < *$3, @$); delete $1; delete $3; }
|
||||
| expr GREATER expr
|
||||
{ $$ = *$1 > *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 > *$3, @$); delete $1; delete $3; }
|
||||
| expr LESS_EQUAL expr
|
||||
{ $$ = *$1 <= *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 <= *$3, @$); delete $1; delete $3; }
|
||||
| expr GREATER_EQUAL expr
|
||||
{ $$ = *$1 >= *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 >= *$3, @$); delete $1; delete $3; }
|
||||
| expr EQUAL_EQUAL expr
|
||||
{ $$ = *$1 == *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 == *$3, @$); delete $1; delete $3; }
|
||||
| expr EXCLAMATION_EQUAL expr
|
||||
{ $$ = *$1 != *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 != *$3, @$); delete $1; delete $3; }
|
||||
| expr LOGICAL_OR expr
|
||||
{ $$ = *$1 || *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 || *$3, @$); delete $1; delete $3; }
|
||||
| expr LOGICAL_AND expr
|
||||
{ $$ = *$1 && *$3; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = *$1 && *$3, @$); delete $1; delete $3; }
|
||||
| MINUS expr %prec UMINUS
|
||||
{ $$ = -*$2; delete $2;}
|
||||
{ TYPERR_CATCH($$ = -*$2, @$); delete $2;}
|
||||
| PLUS expr %prec UPLUS
|
||||
{ $$ = $2; }
|
||||
{ TYPERR_CATCH($$ = +(*$2), @$); delete $2; }
|
||||
| EXCLAMATION expr
|
||||
{ $$ = !*$2; delete $2; }
|
||||
{ TYPERR_CATCH($$ = !*$2, @$); delete $2; }
|
||||
| expr LBRACKET array_expr RBRACKET
|
||||
{ $$ = (*$1)[*$3]; delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = (*$1)[*$3], @$)
|
||||
catch(MacroValue::OutOfBoundsError)
|
||||
{
|
||||
error(@$, "Index out of bounds");
|
||||
}
|
||||
delete $1; delete $3; }
|
||||
| LBRACKET array_expr RBRACKET
|
||||
{ $$ = $2; }
|
||||
| expr COLON expr
|
||||
{ $$ = IntMV::new_range(*$1, *$3); delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = IntMV::new_range(*$1, *$3), @$); delete $1; delete $3; }
|
||||
;
|
||||
|
||||
array_expr : expr
|
||||
{ $$ = $1->toArray(); delete $1; }
|
||||
| array_expr COMMA expr
|
||||
{ $$ = $3->append(*$1); delete $1; delete $3; }
|
||||
{ TYPERR_CATCH($$ = $3->append(*$1), @$); delete $1; delete $3; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
|
@ -28,6 +28,9 @@ MacroDriver::MacroDriver() : trace_scanning(false), trace_parsing(false)
|
|||
|
||||
MacroDriver::~MacroDriver()
|
||||
{
|
||||
for(map<string, MacroValue *>::iterator it = env.begin();
|
||||
it != env.end(); it++)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -48,8 +51,23 @@ MacroDriver::parse(const string &f, ostream &out)
|
|||
}
|
||||
|
||||
void
|
||||
MacroDriver::error(const Macro::parser::location_type &l, const string &m)
|
||||
MacroDriver::error(const Macro::parser::location_type &l, const string &m) const
|
||||
{
|
||||
cerr << "ERROR: " << l << ": " << m << endl;
|
||||
cerr << "ERROR in macro-processor: " << l << ": " << m << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void
|
||||
MacroDriver::set_variable(const string &name, MacroValue *value)
|
||||
{
|
||||
env[name] = value;
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
MacroDriver::get_variable(const string &name) const throw (UnknownVariable)
|
||||
{
|
||||
map<string, MacroValue *>::const_iterator it = env.find(name);
|
||||
if (it == env.end())
|
||||
throw UnknownVariable(name);
|
||||
return (it->second)->clone();
|
||||
}
|
||||
|
|
|
@ -65,7 +65,19 @@ public:
|
|||
//! Implements the macro expansion using a Flex scanner and a Bison parser
|
||||
class MacroDriver
|
||||
{
|
||||
private:
|
||||
//! Environment: maps macro variables to their values
|
||||
map<string, MacroValue *> env;
|
||||
|
||||
public:
|
||||
//! Exception thrown when value of an unknown variable is requested
|
||||
class UnknownVariable
|
||||
{
|
||||
public:
|
||||
const string name;
|
||||
UnknownVariable(const string &name_arg) : name(name_arg) {}
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
MacroDriver();
|
||||
//! Destructor
|
||||
|
@ -80,9 +92,6 @@ public:
|
|||
//! Stack of locations used for (possibly nested) includes
|
||||
stack<Macro::parser::location_type> loc_stack;
|
||||
|
||||
//! Environment (maps macro variables to their values)
|
||||
map<string, MacroValue*> env;
|
||||
|
||||
//! Name of main file being parsed
|
||||
string file;
|
||||
|
||||
|
@ -102,7 +111,15 @@ public:
|
|||
bool trace_parsing;
|
||||
|
||||
//! Error handler
|
||||
void error(const Macro::parser::location_type &l, const string &m);
|
||||
void error(const Macro::parser::location_type &l, const string &m) const;
|
||||
|
||||
//! Set a variable
|
||||
/*! Pointer *value must not be altered nor deleted afterwards, since it is kept by this class */
|
||||
void set_variable(const string &name, MacroValue *value);
|
||||
|
||||
//! Get a variable
|
||||
/*! Returns a newly allocated value (clone of the value stored in environment). */
|
||||
MacroValue *get_variable(const string &name) const throw (UnknownVariable);
|
||||
};
|
||||
|
||||
#endif // ! MACRO_DRIVER_HH
|
||||
|
|
|
@ -23,6 +23,12 @@ MacroValue::~MacroValue()
|
|||
{
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
MacroValue::operator+() const throw (TypeError)
|
||||
{
|
||||
throw TypeError("Unary operator + does not exist for this type");
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
MacroValue::operator-(const MacroValue &mv) const throw (TypeError)
|
||||
{
|
||||
|
@ -32,7 +38,7 @@ MacroValue::operator-(const MacroValue &mv) const throw (TypeError)
|
|||
MacroValue *
|
||||
MacroValue::operator-() const throw (TypeError)
|
||||
{
|
||||
throw TypeError("Operator - does not exist for this type");
|
||||
throw TypeError("Unary operator - does not exist for this type");
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
|
@ -90,17 +96,29 @@ MacroValue::operator!() const throw (TypeError)
|
|||
}
|
||||
|
||||
MacroValue *
|
||||
MacroValue::operator[](const MacroValue &mv) const throw (TypeError)
|
||||
MacroValue::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError)
|
||||
{
|
||||
throw TypeError("Operator [] does not exist for this type");
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
MacroValue::append(const MacroValue &mv) const
|
||||
MacroValue::append(const MacroValue &mv) const throw (TypeError)
|
||||
{
|
||||
throw TypeError("Cannot append an array at the end of another one. Should use concatenation.");
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
MacroValue::new_base_value(int i)
|
||||
{
|
||||
return new IntMV(i);
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
MacroValue::new_base_value(const string &s)
|
||||
{
|
||||
return new StringMV(s);
|
||||
}
|
||||
|
||||
IntMV::IntMV(int value_arg) : value(value_arg)
|
||||
{
|
||||
}
|
||||
|
@ -118,6 +136,12 @@ IntMV::operator+(const MacroValue &mv) const throw (TypeError)
|
|||
return new IntMV(value + mv2->value);
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
IntMV::operator+() const throw (TypeError)
|
||||
{
|
||||
return clone();
|
||||
}
|
||||
|
||||
MacroValue *
|
||||
IntMV::operator-(const MacroValue &mv) const throw (TypeError)
|
||||
{
|
||||
|
@ -254,7 +278,7 @@ IntMV::toArray() const
|
|||
}
|
||||
|
||||
MacroValue *
|
||||
IntMV::append(const MacroValue &array) const
|
||||
IntMV::append(const MacroValue &array) const throw (TypeError)
|
||||
{
|
||||
const ArrayMV<int> *array2 = dynamic_cast<const ArrayMV<int> *>(&array);
|
||||
if (array2 == NULL)
|
||||
|
@ -326,7 +350,7 @@ StringMV::operator!=(const MacroValue &mv) const throw (TypeError)
|
|||
}
|
||||
|
||||
MacroValue *
|
||||
StringMV::operator[](const MacroValue &mv) const throw (TypeError)
|
||||
StringMV::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError)
|
||||
{
|
||||
const ArrayMV<int> *mv2 = dynamic_cast<const ArrayMV<int> *>(&mv);
|
||||
if (mv2 == NULL)
|
||||
|
@ -335,6 +359,8 @@ StringMV::operator[](const MacroValue &mv) const throw (TypeError)
|
|||
for(vector<int>::const_iterator it = mv2->values.begin();
|
||||
it != mv2->values.end(); it++)
|
||||
{
|
||||
if (*it < 1 || *it > (int) value.length())
|
||||
throw OutOfBoundsError();
|
||||
char c = value.at(*it - 1);
|
||||
result.append(&c);
|
||||
}
|
||||
|
@ -362,7 +388,7 @@ StringMV::toArray() const
|
|||
}
|
||||
|
||||
MacroValue *
|
||||
StringMV::append(const MacroValue &array) const
|
||||
StringMV::append(const MacroValue &array) const throw (TypeError)
|
||||
{
|
||||
const ArrayMV<string> *array2 = dynamic_cast<const ArrayMV<string> *>(&array);
|
||||
if (array2 == NULL)
|
||||
|
|
|
@ -37,10 +37,17 @@ public:
|
|||
const string message;
|
||||
TypeError(const string &message_arg) : message(message_arg) {};
|
||||
};
|
||||
//! Exception thrown when doing an out-of-bounds access through [] operator
|
||||
class OutOfBoundsError
|
||||
{
|
||||
};
|
||||
virtual ~MacroValue();
|
||||
//! Applies + operator
|
||||
/*! Returns a newly allocated value */
|
||||
virtual MacroValue *operator+(const MacroValue &mv) const throw (TypeError) = 0;
|
||||
//! Applies unary + operator
|
||||
/*! Returns a newly allocated value */
|
||||
virtual MacroValue *operator+() const throw (TypeError);
|
||||
//! Applies - operator
|
||||
/*! Returns a newly allocated value */
|
||||
virtual MacroValue *operator-(const MacroValue &mv) const throw (TypeError);
|
||||
|
@ -82,7 +89,7 @@ public:
|
|||
virtual MacroValue *operator!() const throw (TypeError);
|
||||
//! Applies [] operator
|
||||
/*! Returns a newly allocated value */
|
||||
virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError);
|
||||
virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError);
|
||||
//! Converts value to string
|
||||
virtual string toString() const = 0;
|
||||
//! Clones value
|
||||
|
@ -93,7 +100,13 @@ public:
|
|||
virtual MacroValue *toArray() const = 0;
|
||||
//! Appends value at the end of an array
|
||||
/*! The first argument must be an array. Returns a newly allocated array. */
|
||||
virtual MacroValue *append(const MacroValue &array) const;
|
||||
virtual MacroValue *append(const MacroValue &array) const throw (TypeError);
|
||||
//! Returns a new IntMV
|
||||
/*! Necessary for ArrayMV::operator[] (template issue) */
|
||||
static MacroValue *new_base_value(int i);
|
||||
//! Returns a new StringMV
|
||||
/*! Necessary for ArrayMV::operator[] (template issue) */
|
||||
static MacroValue *new_base_value(const string &s);
|
||||
};
|
||||
|
||||
//! Represents an integer value in macro language
|
||||
|
@ -109,6 +122,9 @@ public:
|
|||
//! Computes arithmetic addition
|
||||
/*! Returns a newly allocated value */
|
||||
virtual MacroValue *operator+(const MacroValue &mv) const throw (TypeError);
|
||||
//! Unary plus
|
||||
/*! Returns a clone of itself */
|
||||
virtual MacroValue *operator+() const throw (TypeError);
|
||||
//! Computes arithmetic substraction
|
||||
/*! Returns a newly allocated value */
|
||||
virtual MacroValue *operator-(const MacroValue &mv) const throw (TypeError);
|
||||
|
@ -143,7 +159,7 @@ public:
|
|||
virtual MacroValue *toArray() const;
|
||||
//! Appends value at the end of an array
|
||||
/*! The first argument must be an integer array. Returns a newly allocated integer array. */
|
||||
virtual MacroValue *append(const MacroValue &array) const;
|
||||
virtual MacroValue *append(const MacroValue &array) const throw (TypeError);
|
||||
//! Creates a integer range
|
||||
/*! Arguments must be of type IntMV.
|
||||
Returns a newly allocated integer array containing all integers between mv1 and mv2.
|
||||
|
@ -168,10 +184,8 @@ public:
|
|||
virtual MacroValue *operator!=(const MacroValue &mv) const throw (TypeError);
|
||||
//! Subscripting operator
|
||||
/*! Argument must be an ArrayMV<int>. Indexes begin at 1.
|
||||
Returns a newly allocated string.
|
||||
\todo Add bound error checking
|
||||
*/
|
||||
virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError);
|
||||
Returns a newly allocated string. */
|
||||
virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError);
|
||||
//! Returns underlying string value
|
||||
virtual string toString() const;
|
||||
virtual MacroValue *clone() const;
|
||||
|
@ -180,10 +194,11 @@ public:
|
|||
virtual MacroValue *toArray() const;
|
||||
//! Appends value at the end of an array
|
||||
/*! The first argument must be a string array. Returns a newly allocated string array. */
|
||||
virtual MacroValue *append(const MacroValue &array) const;
|
||||
virtual MacroValue *append(const MacroValue &array) const throw (TypeError);
|
||||
};
|
||||
|
||||
//! Represents an array in macro language
|
||||
/*! Empty arrays are forbidden */
|
||||
template<typename T>
|
||||
class ArrayMV : public MacroValue
|
||||
{
|
||||
|
@ -204,20 +219,21 @@ public:
|
|||
virtual MacroValue *operator!=(const MacroValue &mv) const throw (TypeError);
|
||||
//! Subscripting operator
|
||||
/*! Argument must be an ArrayMV<int>. Indexes begin at 1.
|
||||
Returns a newly allocated array.
|
||||
\todo Add bound error checking
|
||||
*/
|
||||
virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError);
|
||||
If argument is a one-element array, returns a newly-allocated IntMV or String.
|
||||
Otherwise returns a newly allocated array. */
|
||||
virtual MacroValue *operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError);
|
||||
//! Returns a string containing the concatenation of string representations of elements
|
||||
virtual string toString() const;
|
||||
virtual MacroValue *clone() const;
|
||||
//! Returns itself
|
||||
//! Returns a clone of itself
|
||||
virtual MacroValue *toArray() const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ArrayMV<T>::ArrayMV(const vector<T> &values_arg) : values(values_arg)
|
||||
{
|
||||
if (values.size() == 0)
|
||||
throw "Empty arrays forbidden";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -262,7 +278,7 @@ ArrayMV<T>::operator!=(const MacroValue &mv) const throw (TypeError)
|
|||
|
||||
template<typename T>
|
||||
MacroValue *
|
||||
ArrayMV<T>::operator[](const MacroValue &mv) const throw (TypeError)
|
||||
ArrayMV<T>::operator[](const MacroValue &mv) const throw (TypeError, OutOfBoundsError)
|
||||
{
|
||||
const ArrayMV<int> *mv2 = dynamic_cast<const ArrayMV<int> *>(&mv);
|
||||
if (mv2 == NULL)
|
||||
|
@ -270,8 +286,16 @@ ArrayMV<T>::operator[](const MacroValue &mv) const throw (TypeError)
|
|||
vector<T> result;
|
||||
for(vector<int>::const_iterator it = mv2->values.begin();
|
||||
it != mv2->values.end(); it++)
|
||||
result.push_back(values[*it - 1]);
|
||||
return new ArrayMV<T>(result);
|
||||
{
|
||||
if (*it < 1 || *it > (int) values.size())
|
||||
throw OutOfBoundsError();
|
||||
result.push_back(values[*it - 1]);
|
||||
}
|
||||
|
||||
if (result.size() > 1)
|
||||
return new ArrayMV<T>(result);
|
||||
else
|
||||
return MacroValue::new_base_value(result[0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
Loading…
Reference in New Issue