next up previous
Next: Details of the MIR Up: The MIR Format Previous: The MIR Format


Node-subclass prototypes

The indexNode class simply acts as a superclass for constNode and idNode:

class indexNode : public exprNode {
  indexNode(NodeType typ, typeNode * type, const Coord coord);
};

class constNode : public indexNode { ... };
class idNode : public indexNode { ... };

The conditiongotoNode class corresponds to a conditional branch in the ISA. At the MIR level, all control flow structures in the input AST are represented by combinations of conditiongotoNodes, gotoNodes, and labelNodes. The Operator in the op field of the conditiongotoNode must be a relational operator (eg: <, <=, ==, etc.).

class conditiongotoNode : public gotoNode {
  conditiongotoNode(labelNode * label, indexNode * left, unsigned int op_id,
                    indexNode * right, const Coord coord = Coord::Unknown);
  void left(indexNode * left);
  indexNode * left(void);
  void right(indexNode * right);
  indexNode * right(void);
  void op(Operator * op);
  Operator * op(void);
};

The operandNode class represents a memory location or address.

class operandNode : public exprNode {
  operandNode(indexNode * the_var, const Coord coord = Coord::Unknown);
  operandNode(indexNode * the_var, bool star, bool addr, 
              const Coord coord = Coord::Unknown);
  operandNode(indexNode * the_var, bool star, bool addr, id_list * fields, 
              indexNode * array_index, const Coord coord = Coord::Unknown);

  void addr(bool addr) { _addr = addr; }
  bool addr() { return _addr; }
  void star(bool star) { _star = star; }
  bool star() { return _star; }
  void cast(typeNode * cast) { _cast = cast; }
  typeNode * cast(void) { return _cast; }
  const typeNode * cast(void) const { return _cast; }
  inline id_list & fields() { return _fields; }
  inline const id_list & fields() const { return _fields; }
  void index(indexNode * index) { _index = index; }
  indexNode * index(void) { return _index; }
  const indexNode * index(void) const { return _index; }
  void var(indexNode * var) { _var = var; }
  indexNode * var(void) { return _var; }
  const indexNode * var(void) const { return _var; }
};

An operandNode represents a simple variable or constant when only the var field is set. Otherwise, it represents a memory location (or the address of a memory location) that can be loaded in a single instruction. This latter case assumes that the base address of the var field is already loaded into a register and the offset is either constant or already computed. In a grammatical sense, the operandNode is defined by the following rules:

\begin{eqnarray*}
operand & \rightarrow & [typecast][\texttt{\&}] (\texttt{*} va...
...t][\texttt{\&}] var \{.field\}^*
[ \texttt{[} index \texttt{]}]
\end{eqnarray*}

The threeAddrNode is the quintessential form for all arithmetic statements in the dismantler's output:

class threeAddrNode : public stmtNode {
 public:
  // a = b;
  threeAddrNode(operandNode * lhs, operandNode * rhs, 
                const Coord coord = Coord::Unknown);
  // a = -b;
  threeAddrNode(operandNode * lhs, unsigned int op_id, 
                operandNode * rhs, const Coord coord = Coord::Unknown);
  // a = sizeof(<type>)
  threeAddrNode(operandNode * lhs, typeNode * type,
                const Coord coord = Coord::Unknown);
  // a = b (op) c;
  threeAddrNode(operandNode * lhs, operandNode * rhs1, unsigned int op_id,
                operandNode * rhs2, const Coord coord = Coord::Unknown);
  // a = b(...);
  threeAddrNode(operandNode * lhs, operandNode * func, 
                operand_list * arg_list, const Coord coord = Coord::Unknown);
  // a(...);
  threeAddrNode(operandNode * func, operand_list * arg_list, 
                const Coord coord = Coord::Unknown);

  void lhs(operandNode * lhs);
  operandNode * lhs(void);
  void rhs1(operandNode * rhs1);
  operandNode * rhs1(void);
  void op(Operator * op);
  Operator * op(void);
  void rhs2(operandNode * rhs2);
  operandNode * rhs2(void);
  void sizeof_type(typeNode * type);
  typeNode * sizeof_type(void);
  inline operand_list & arg_list();
  inline const operand_list & arg_list() const;
};

Using threeAddrNode, we can represent assignment of variables, unary operations to operands, binary operations to operands, function calls, and determining the sizeof a type or operand. For function calls, the assignment is optional. The following grammar describes the forms that a threeAddrNode can take.

\begin{eqnarray*}
threeAddrNode & \rightarrow & \texttt{lhs} = [unaryOperator]\ ...
...est \\
& \rightarrow & \epsilon\\
arg & \rightarrow & operand
\end{eqnarray*}


next up previous
Next: Details of the MIR Up: The MIR Format Previous: The MIR Format
Adam C. Brown 2006-01-26