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
<< " at " << get_fileline() << endl;
operand1()->dump(out, indent+4);
operand2()->dump(out, indent+4);
dump_operands(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
{
out << setw(indent) << "" << "Integer" << endl;
out << setw(indent) << "" << "Integer " << value_
<< " at " << get_fileline() << endl;
}
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
<< " at " << get_fileline() << endl;
operand1()->dump(out, indent+4);
operand2()->dump(out, indent+4);
dump_operands(out, indent+4);
}
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_ << "\")"
<< " 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_;
}
ExpUnary::ExpUnary(Expression*op1)
: operand1_(op1)
{
}
ExpUnary::~ExpUnary()
{
delete operand1_;
}
ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(op)
{
@ -84,3 +94,21 @@ ExpName::ExpName(perm_string nn)
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.
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.
virtual void dump(ostream&out, int indent) const =0;
@ -58,6 +65,20 @@ class Expression : public LineInfo {
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
* of binary operators.
@ -69,10 +90,11 @@ class ExpBinary : public Expression {
~ExpBinary();
protected:
inline Expression* operand1() { return operand1_; }
inline Expression* operand2() { return operand2_; }
inline const Expression* operand1() const { return operand1_; }
inline const Expression* operand2() const { return operand2_; }
int emit_operand1(ostream&out, Entity*ent, Architecture*arc);
int emit_operand2(ostream&out, Entity*ent, Architecture*arc);
void dump_operands(ostream&out, int indent) const;
private:
Expression*operand1_;
@ -102,6 +124,7 @@ class ExpInteger : public Expression {
~ExpInteger();
int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
bool evaluate(int64_t&val) const;
void dump(ostream&out, int indent) const;
@ -136,11 +159,31 @@ class ExpName : public Expression {
~ExpName();
int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
void dump(ostream&out, int indent) const;
private:
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

View File

@ -31,11 +31,43 @@ int Expression::emit(ostream&out, Entity*, Architecture*)
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 errors = 0;
errors += operand1()->emit(out, ent, arc);
errors += emit_operand1(out, ent, arc);
switch (fun_) {
case PLUS:
@ -61,23 +93,27 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
break;
}
errors += operand2()->emit(out, ent, arc);
errors += emit_operand2(out, ent, arc);
return errors;
}
int ExpInteger::emit(ostream&out, Entity*, Architecture*)
{
out << " /* " << get_fileline() << ": internal error: "
<< "INTEGER LITERAL */ ";
return 1;
out << value_;
return 0;
}
bool ExpInteger::is_primary(void) const
{
return true;
}
int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
errors += operand1()->emit(out, ent, arc);
errors += emit_operand1(out, ent, arc);
switch (fun_) {
case AND:
@ -100,7 +136,7 @@ int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc)
break;
}
errors += operand2()->emit(out, ent, arc);
errors += emit_operand2(out, ent, arc);
return errors;
}
@ -112,3 +148,26 @@ int ExpName::emit(ostream&out, Entity*, Architecture*)
out << name_;
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);
$$ = 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; } ;
@ -384,6 +394,8 @@ primary
FILE_NAME(tmp, @1);
$$ = tmp;
}
| '(' expression ')'
{ $$ = $2; }
;
relation : shift_expression { $$ = $1; } ;