Add support for unary abs and not operators.

While I'm at it, do a little refactoring of the handling of binary
expressions to reduce code duplication.
This commit is contained in:
Stephen Williams 2011-02-20 17:03:46 -08:00
parent cbb213d79e
commit e172b4d9bc
5 changed files with 180 additions and 16 deletions

View File

@ -145,13 +145,19 @@ void ExpArithmetic::dump(ostream&out, int indent) const
out << setw(indent) << "" << "Arithmetic " << fun_name out << setw(indent) << "" << "Arithmetic " << fun_name
<< " at " << get_fileline() << endl; << " at " << get_fileline() << endl;
operand1()->dump(out, indent+4); dump_operands(out, indent+4);
operand2()->dump(out, indent+4); }
void ExpBinary::dump_operands(ostream&out, int indent) const
{
operand1_->dump(out, indent);
operand2_->dump(out, indent);
} }
void ExpInteger::dump(ostream&out, int indent) const void ExpInteger::dump(ostream&out, int indent) const
{ {
out << setw(indent) << "" << "Integer" << endl; out << setw(indent) << "" << "Integer " << value_
<< " at " << get_fileline() << endl;
} }
void ExpLogical::dump(ostream&out, int indent) const void ExpLogical::dump(ostream&out, int indent) const
@ -180,8 +186,7 @@ void ExpLogical::dump(ostream&out, int indent) const
out << setw(indent) << "" << "Logical " << fun_name out << setw(indent) << "" << "Logical " << fun_name
<< " at " << get_fileline() << endl; << " at " << get_fileline() << endl;
operand1()->dump(out, indent+4); dump_operands(out, indent+4);
operand2()->dump(out, indent+4);
} }
void ExpName::dump(ostream&out, int indent) const void ExpName::dump(ostream&out, int indent) const
@ -189,3 +194,20 @@ void ExpName::dump(ostream&out, int indent) const
out << setw(indent) << "" << "ExpName(\"" << name_ << "\")" out << setw(indent) << "" << "ExpName(\"" << name_ << "\")"
<< " at " << get_fileline() << endl; << " at " << get_fileline() << endl;
} }
void ExpUAbs::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "abs() at " << get_fileline() << endl;
dump_operand1(out, indent+4);
}
void ExpUnary::dump_operand1(ostream&out, int indent) const
{
operand1_->dump(out, indent);
}
void ExpUNot::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "not() at " << get_fileline() << endl;
dump_operand1(out, indent+4);
}

View File

@ -43,6 +43,16 @@ ExpBinary::~ExpBinary()
delete operand2_; delete operand2_;
} }
ExpUnary::ExpUnary(Expression*op1)
: operand1_(op1)
{
}
ExpUnary::~ExpUnary()
{
delete operand1_;
}
ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2) ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(op) : ExpBinary(op1, op2), fun_(op)
{ {
@ -84,3 +94,21 @@ ExpName::ExpName(perm_string nn)
ExpName::~ExpName() ExpName::~ExpName()
{ {
} }
ExpUAbs::ExpUAbs(Expression*op1)
: ExpUnary(op1)
{
}
ExpUAbs::~ExpUAbs()
{
}
ExpUNot::ExpUNot(Expression*op1)
: ExpUnary(op1)
{
}
ExpUNot::~ExpUNot()
{
}

View File

@ -48,6 +48,13 @@ class Expression : public LineInfo {
// cannot be done. // cannot be done.
virtual bool evaluate(int64_t&val) const; virtual bool evaluate(int64_t&val) const;
// This method returns true if the drawn Verilog for this
// expression is a primary. A containing expressin can use
// this method to know if it needs to wrap parentheses. This
// is somewhile optional, so it is better to return false if
// not certain. The default implementation does return false.
virtual bool is_primary(void) const;
// Debug dump of the expression. // Debug dump of the expression.
virtual void dump(ostream&out, int indent) const =0; virtual void dump(ostream&out, int indent) const =0;
@ -58,6 +65,20 @@ class Expression : public LineInfo {
Expression& operator = (const Expression&); Expression& operator = (const Expression&);
}; };
class ExpUnary : public Expression {
public:
ExpUnary(Expression*op1);
~ExpUnary();
protected:
int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
void dump_operand1(ostream&out, int indent) const;
private:
Expression*operand1_;
};
/* /*
* This is an abstract class that collects some of the common features * This is an abstract class that collects some of the common features
* of binary operators. * of binary operators.
@ -69,10 +90,11 @@ class ExpBinary : public Expression {
~ExpBinary(); ~ExpBinary();
protected: protected:
inline Expression* operand1() { return operand1_; }
inline Expression* operand2() { return operand2_; } int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
inline const Expression* operand1() const { return operand1_; } int emit_operand2(ostream&out, Entity*ent, Architecture*arc);
inline const Expression* operand2() const { return operand2_; }
void dump_operands(ostream&out, int indent) const;
private: private:
Expression*operand1_; Expression*operand1_;
@ -102,6 +124,7 @@ class ExpInteger : public Expression {
~ExpInteger(); ~ExpInteger();
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
bool evaluate(int64_t&val) const; bool evaluate(int64_t&val) const;
void dump(ostream&out, int indent) const; void dump(ostream&out, int indent) const;
@ -136,11 +159,31 @@ class ExpName : public Expression {
~ExpName(); ~ExpName();
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
void dump(ostream&out, int indent) const; void dump(ostream&out, int indent) const;
private: private:
perm_string name_; perm_string name_;
}; };
class ExpUAbs : public ExpUnary {
public:
ExpUAbs(Expression*op1);
~ExpUAbs();
int emit(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent) const;
};
class ExpUNot : public ExpUnary {
public:
ExpUNot(Expression*op1);
~ExpUNot();
int emit(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent) const;
};
#endif #endif

View File

@ -31,11 +31,43 @@ int Expression::emit(ostream&out, Entity*, Architecture*)
return 1; return 1;
} }
bool Expression::is_primary(void) const
{
return false;
}
int ExpBinary::emit_operand1(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
bool oper_primary = operand1_->is_primary();
if (! oper_primary) out << "(";
errors += operand1_->emit(out, ent, arc);
if (! oper_primary) out << ")";
return errors;
}
int ExpBinary::emit_operand2(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
bool oper_primary = operand2_->is_primary();
if (! oper_primary) out << "(";
errors += operand2_->emit(out, ent, arc);
if (! oper_primary) out << ")";
return errors;
}
int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
errors += operand1_->emit(out, ent, arc);
return errors;
}
int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
{ {
int errors = 0; int errors = 0;
errors += operand1()->emit(out, ent, arc); errors += emit_operand1(out, ent, arc);
switch (fun_) { switch (fun_) {
case PLUS: case PLUS:
@ -61,23 +93,27 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
break; break;
} }
errors += operand2()->emit(out, ent, arc); errors += emit_operand2(out, ent, arc);
return errors; return errors;
} }
int ExpInteger::emit(ostream&out, Entity*, Architecture*) int ExpInteger::emit(ostream&out, Entity*, Architecture*)
{ {
out << " /* " << get_fileline() << ": internal error: " out << value_;
<< "INTEGER LITERAL */ "; return 0;
return 1; }
bool ExpInteger::is_primary(void) const
{
return true;
} }
int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc) int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc)
{ {
int errors = 0; int errors = 0;
errors += operand1()->emit(out, ent, arc); errors += emit_operand1(out, ent, arc);
switch (fun_) { switch (fun_) {
case AND: case AND:
@ -100,7 +136,7 @@ int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc)
break; break;
} }
errors += operand2()->emit(out, ent, arc); errors += emit_operand2(out, ent, arc);
return errors; return errors;
} }
@ -112,3 +148,26 @@ int ExpName::emit(ostream&out, Entity*, Architecture*)
out << name_; out << name_;
return errors; return errors;
} }
bool ExpName::is_primary(void) const
{
return true;
}
int ExpUAbs::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "abs(";
errors += emit_operand1(out, ent, arc);
out << ")";
return errors;
}
int ExpUNot::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "~(";
errors += emit_operand1(out, ent, arc);
out << ")";
return errors;
}

View File

@ -294,6 +294,16 @@ factor
FILE_NAME(tmp, @2); FILE_NAME(tmp, @2);
$$ = tmp; $$ = tmp;
} }
| K_abs primary
{ ExpUAbs*tmp = new ExpUAbs($2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_not primary
{ ExpUNot*tmp = new ExpUNot($2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
; ;
identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ; identifier_opt : IDENTIFIER { $$ = $1; } | { $$ = 0; } ;
@ -384,6 +394,8 @@ primary
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| '(' expression ')'
{ $$ = $2; }
; ;
relation : shift_expression { $$ = $1; } ; relation : shift_expression { $$ = $1; } ;