Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision bb7422a92c2e0bb9b901b7099d87e5736fed1d23)
+++ src/Parser/ParseNode.h	(revision a33a5e288e95b952ea8dfff1ae1d0dbe375521e6)
@@ -441,4 +441,8 @@
 ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
+ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
+ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
+ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
+ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision bb7422a92c2e0bb9b901b7099d87e5736fed1d23)
+++ src/Parser/StatementNode.cc	(revision a33a5e288e95b952ea8dfff1ae1d0dbe375521e6)
@@ -377,7 +377,7 @@
 ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
 	auto clause = new ast::WaitForClause( location );
-	clause->target_func = maybeBuild( targetExpr );
+	clause->target = maybeBuild( targetExpr );
 	clause->stmt = maybeMoveBuild( stmt );
-	clause->cond = notZeroExpr( maybeMoveBuild( when ) );
+	clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
 
 	ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
@@ -408,4 +408,93 @@
 	return existing;
 } // build_waitfor_timeout
+
+ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
+    ast::WhenClause * clause = new ast::WhenClause( loc );
+    clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
+    clause->stmt = maybeMoveBuild( stmt );
+    clause->target = maybeMoveBuild( targetExpr );
+    return new ast::WaitUntilStmt::ClauseNode( clause );
+}
+ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
+    ast::WhenClause * clause = new ast::WhenClause( loc );
+    clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
+    clause->stmt = maybeMoveBuild( stmt );
+    return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
+}
+ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
+    ast::WhenClause * clause = new ast::WhenClause( loc );
+    clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
+    clause->stmt = maybeMoveBuild( stmt );
+    clause->target = maybeMoveBuild( timeout );
+    return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause );
+}
+
+ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
+    ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
+    retStmt->predicateTree = root;
+    
+    // iterative tree traversal
+    std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
+    ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
+    ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
+    ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
+    nodeStack.push_back(root);
+
+    do {
+        currNode = nodeStack.back();
+        nodeStack.pop_back(); // remove node since it will be processed
+
+        switch (currNode->op) {
+            case ast::WaitUntilStmt::ClauseNode::LEAF:
+                retStmt->clauses.push_back(currNode->leaf);
+                break;
+            case ast::WaitUntilStmt::ClauseNode::ELSE:
+                retStmt->else_stmt = currNode->leaf->stmt 
+                    ? ast::deepCopy( currNode->leaf->stmt )
+                    : nullptr;
+                
+                retStmt->else_cond = currNode->leaf->when_cond
+                    ? ast::deepCopy( currNode->leaf->when_cond )
+                    : nullptr;
+
+                delete currNode->leaf;
+                break;
+            case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
+                retStmt->timeout_time = currNode->leaf->target 
+                    ? ast::deepCopy( currNode->leaf->target )
+                    : nullptr;
+                retStmt->timeout_stmt = currNode->leaf->stmt
+                    ? ast::deepCopy( currNode->leaf->stmt )
+                    : nullptr;
+                retStmt->timeout_cond = currNode->leaf->when_cond
+                    ? ast::deepCopy( currNode->leaf->when_cond )
+                    : nullptr;
+
+                delete currNode->leaf;
+                break;
+            default:
+                nodeStack.push_back( currNode->right ); // process right after left
+                nodeStack.push_back( currNode->left );
+
+                // Cut else/timeout out of the tree
+                if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
+                    if ( lastInternalNode )
+                        lastInternalNode->right = currNode->left;
+                    else    // if not set then root is LEFT_OR 
+                        retStmt->predicateTree = currNode->left;
+    
+                    currNode->left = nullptr;
+                    cleanup = currNode;
+                }
+                
+                lastInternalNode = currNode;
+                break;
+        }
+    } while ( !nodeStack.empty() );
+
+    if ( cleanup ) delete cleanup;
+
+    return retStmt;
+}
 
 ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision bb7422a92c2e0bb9b901b7099d87e5736fed1d23)
+++ src/Parser/parser.yy	(revision a33a5e288e95b952ea8dfff1ae1d0dbe375521e6)
@@ -304,4 +304,5 @@
 	StatementNode * sn;
 	ast::WaitForStmt * wfs;
+    ast::WaitUntilStmt::ClauseNode * wuscn;
 	ast::Expr * constant;
 	CondCtl * ifctl;
@@ -425,5 +426,6 @@
 %type<en> when_clause					when_clause_opt				waitfor		waituntil		timeout
 %type<sn> waitfor_statement				waituntil_statement
-%type<wfs> wor_waitfor_clause			waituntil_clause			wand_waituntil_clause	wor_waituntil_clause
+%type<wfs> wor_waitfor_clause
+%type<wuscn> waituntil_clause			wand_waituntil_clause       wor_waituntil_clause
 
 // declarations
@@ -1683,30 +1685,33 @@
 waituntil_clause:
 	when_clause_opt waituntil statement
-		{ printf( "waituntil_clause 1\n" ); $$ = nullptr; }
+		{ $$ = build_waituntil_clause( yylloc, $1, $2, maybe_build_compound( yylloc, $3 ) ); }
 	| '(' wor_waituntil_clause ')'
-		{ printf( "waituntil_clause 2\n" ); $$ = nullptr; }
+		{ $$ = $2; }
 	;
 
 wand_waituntil_clause:
 	waituntil_clause									%prec THEN
-		{ printf( "wand_waituntil_clause 1\n" ); $$ = nullptr; }
+		{ $$ = $1; }
 	| waituntil_clause wand wand_waituntil_clause
-		{ printf( "wand_waituntil_clause 2\n" ); $$ = nullptr; }
+		{ $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::AND, $1, $3 ); }
 	;
 
 wor_waituntil_clause:
 	wand_waituntil_clause
-		{ printf( "wor_waituntil_clause 1\n" ); $$ = nullptr; }
+		{ $$ = $1; }
 	| wor_waituntil_clause wor wand_waituntil_clause
-		{ printf( "wor_waituntil_clause 2\n" ); $$ = nullptr; }
+		{ $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR, $1, $3 ); }
 	| wor_waituntil_clause wor when_clause_opt ELSE statement
-		{ printf( "wor_waituntil_clause 3\n" ); $$ = nullptr; }
+		{ $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_else( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
 	| wor_waituntil_clause wor when_clause_opt timeout statement	%prec THEN
-		{ printf( "wor_waituntil_clause 4\n" ); $$ = nullptr; }
+		{ $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }
 	// "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
 	| wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
 		{ SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
 	| wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
-		{ printf( "wor_waituntil_clause 6\n" ); $$ = nullptr; }
+		{ $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1,
+                new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR, 
+                    build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ), 
+                    build_waituntil_else( yylloc, $7, maybe_build_compound( yylloc, $9 ) ) ) ); }
 	;
 
@@ -1714,5 +1719,8 @@
 	wor_waituntil_clause								%prec THEN
 		// SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement.
-		{ $$ = new StatementNode( build_compound( yylloc, nullptr ) ); }
+		{
+            $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) );
+            // $$ = new StatementNode( build_compound( yylloc, nullptr ) );
+        }
 	;
 
