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:
parent
cbb213d79e
commit
e172b4d9bc
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; } ;
|
||||
|
|
|
|||
Loading…
Reference in New Issue