Can someone explain in simple terms to me what a directed acyclic graph is? I have looked on Wikipedia but it doesn\'t really make me see its use in programming.
From a source code or even three address(TAC) code perspective you can visualize the problem really easily at this page...
http://cgm.cs.mcgill.ca/~hagha/topic30/topic30.html#Exptree
If you go to the expression tree section, and then page down a bit it shows the "topological sorting" of the tree, and the algorithm for how to evaluate the expression.
So in that case you can use the DAG to evaluate expressions, which is handy since evaluation is normally interpreted and using such a DAG evaluator will make simple intrepreters faster in principal because it is not pushing and popping to a stack and also because it is eliminating common sub-expressions.
The basic algorithm to compute the DAG in non ancient egyptian(ie English) is this:
1) Make your DAG object like so
You need a live list and this list holds all the current live DAG nodes and DAG sub-expressions. A DAG sub expression is a DAG Node, or you can also call it an internal node. What I mean by live DAG Node is that if you assign to a variable X then it becomes live. A common sub-expression that then uses X uses that instance. If X is assigned to again then a NEW DAG NODE is created and added to the live list and the old X is removed so the next sub-expression that uses X will refer to the new instance and thus will not conflict with sub-expressions that merely use the same variable name.
Once you assign to a variable X, then co-incidentally all the DAG sub-expression nodes that are live at the point of assignment become not-live, since the new assignment invalidates the meaning of sub expressions using the old value.
class Dag {
  TList LiveList;
  DagNode Root;
}
// In your DagNode you need a way to refer to the original things that
// the DAG is computed from. In this case I just assume an integer index
// into the list of variables and also an integer index for the opertor for
// Nodes that refer to operators. Obviously you can create sub-classes for
// different kinds of Dag Nodes.
class DagNode {
  int Variable;
  int Operator;// You can also use a class
  DagNode Left;
  DagNode Right;
  DagNodeList Parents;
}
So what you do is walk through your tree in your own code, such as a tree of expressions in source code for example. Call the existing nodes XNodes for example.
So for each XNode you need to decide how to add it into the DAG, and there is the possibility that it is already in the DAG.
This is very simple pseudo code. Not intended for compilation.
DagNode XNode::GetDagNode(Dag dag) {
  if (XNode.IsAssignment) {
    // The assignment is a special case. A common sub expression is not
    // formed by the assignment since it creates a new value.
    // Evaluate the right hand side like normal
    XNode.RightXNode.GetDagNode();  
    // And now take the variable being assigned to out of the current live list
    dag.RemoveDagNodeForVariable(XNode.VariableBeingAssigned);
    // Also remove all DAG sub expressions using the variable - since the new value
    // makes them redundant
    dag.RemoveDagExpressionsUsingVariable(XNode.VariableBeingAssigned);
    // Then make a new variable in the live list in the dag, so that references to
    // the variable later on will see the new dag node instead.
    dag.AddDagNodeForVariable(XNode.VariableBeingAssigned);
  }
  else if (XNode.IsVariable) {
    // A variable node has no child nodes, so you can just proces it directly
    DagNode n = dag.GetDagNodeForVariable(XNode.Variable));
    if (n) XNode.DagNode = n;
    else {
      XNode.DagNode = dag.CreateDagNodeForVariable(XNode.Variable);
    }
    return XNode.DagNode;
  }
  else if (XNode.IsOperator) {
    DagNode leftDagNode = XNode.LeftXNode.GetDagNode(dag);
    DagNode rightDagNode = XNode.RightXNode.GetDagNode(dag);
    // Here you can observe how supplying the operator id and both operands that it
    // looks in the Dags live list to check if this expression is already there. If
    // it is then it returns it and that is how a common sub-expression is formed.
    // This is called an internal node.
    XNode.DagNode = 
      dag.GetOrCreateDagNodeForOperator(XNode.Operator,leftDagNode,RightDagNode) );
    return XNode.DagNode;
  }
}
So that is one way of looking at it. A basic walk of the tree and just adding in and referring to the Dag nodes as it goes. The root of the dag is whatever DagNode the root of the tree returns for example.
Obviously the example procedure can be broken up into smaller parts or made as sub-classes with virtual functions.
As for sorting the Dag, you go through each DagNode from left to right. In other words follow the DagNodes left hand edge, and then the right hand side edge. The numbers are assigned in reverse. In other words when you reach a DagNode with no children, assign that Node the current sorting number and increment the sorting number, so as the recursion unwinds the numbers get assigned in increasing order.
This example only handles trees with nodes that have zero or two children. Obviously some trees have nodes with more than two children so the logic is still the same. Instead of computing left and right, compute from left to right etc...
// Most basic DAG topological ordering example.
void DagNode::OrderDAG(int* counter) {
  if (this->AlreadyCounted) return;
  // Count from left to right
  for x = 0 to this->Children.Count-1
    this->Children[x].OrderDag(counter)
  // And finally number the DAG Node here after all
  // the children have been numbered
  this->DAGOrder = *counter;
  // Increment the counter so the caller gets a higher number
  *counter = *counter + 1;
  // Mark as processed so will count again
  this->AlreadyCounted = TRUE;
}