Implement simplified substitution for function-like macro invocation.

This supports function-like macro invocation but without any argument
substitution. This now makes test 11 through 14 pass.
diff --git a/glcpp-parse.y b/glcpp-parse.y
index 830a623..60b414e 100644
--- a/glcpp-parse.y
+++ b/glcpp-parse.y
@@ -127,20 +127,14 @@
 
 %}
 
-%union {
-	int ival;
-	char *str;
-	token_t *token;
-	token_list_t *token_list;
-}
-
 %parse-param {glcpp_parser_t *parser}
 %lex-param {glcpp_parser_t *parser}
 
-%token HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH IDENTIFIER NEWLINE OTHER HASH_UNDEF
+%token HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_UNDEF IDENTIFIER NEWLINE OTHER SPACE
 %token LEFT_SHIFT RIGHT_SHIFT LESS_OR_EQUAL GREATER_OR_EQUAL EQUAL NOT_EQUAL AND OR PASTE
 %type <ival> punctuator
-%type <str> IDENTIFIER OTHER
+%type <str> IDENTIFIER OTHER SPACE
+%type <string_list> identifier_list
 %type <token> preprocessing_token
 %type <token_list> pp_tokens replacement_list text_line
 
@@ -169,8 +163,12 @@
 	HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE {
 		_define_object_macro (parser, $2, $3);
 	}
-|	HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE
-|	HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE
+|	HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE {
+		_define_function_macro (parser, $2, NULL, $5);
+	}
+|	HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
+		_define_function_macro (parser, $2, $4, $6);
+	}
 |	HASH_UNDEF IDENTIFIER NEWLINE {
 		string_list_t *macro = hash_table_find (parser->defines, $2);
 		if (macro) {
@@ -186,8 +184,16 @@
 ;
 
 identifier_list:
-	IDENTIFIER
-|	identifier_list ',' IDENTIFIER
+	IDENTIFIER {
+		$$ = _string_list_create (parser);
+		_string_list_append_item ($$, $1);
+		talloc_steal ($$, $1);
+	}
+|	identifier_list ',' IDENTIFIER {
+		$$ = $1;	
+		_string_list_append_item ($$, $3);
+		talloc_steal ($$, $3);
+	}
 ;
 
 text_line:
@@ -227,6 +233,9 @@
 |	OTHER {
 		$$ = _token_create_str (parser, OTHER, $1);
 	}
+|	SPACE {
+		$$ = _token_create_str (parser, OTHER, $1);
+	}
 ;
 
 punctuator:
@@ -649,7 +658,14 @@
 		return TOKEN_CLASS_OBJ_MACRO;
 }
 
-void
+/* Print a non-macro token, or the expansion of an object-like macro.
+ *
+ * Returns 0 if this token is completely printed.
+ *
+ * Returns 1 in the case that 'token' is a function-like macro that
+ * needs further expansion.
+ */
+static int
 _glcpp_parser_print_expanded_token (glcpp_parser_t *parser,
 				    token_t *token)
 {
@@ -659,7 +675,7 @@
 	/* We only expand identifiers */
 	if (token->type != IDENTIFIER) {
 		_token_print (token);
-		return;
+		return 0;
 	}
 
 	/* Look up this identifier in the hash table. */
@@ -669,20 +685,135 @@
 	/* Not a macro, so just print directly. */
 	if (macro == NULL) {
 		printf ("%s", identifier);
-		return;
+		return 0;
 	}
 
-	/* We're not (yet) supporting function-like macros. */
+	/* For function-like macros return 1 for further processing. */
 	if (macro->is_function) {
-		printf ("%s", identifier);
-		return;
+		return 1;
 	}
 
 	/* Finally, don't expand this macro if we're already actively
 	 * expanding it, (to avoid infinite recursion). */
 	if (_string_list_contains (parser->active, identifier, NULL)) {
 		printf ("%s", identifier);
+		return 0;
+	}
+
+	_string_list_push (parser->active, identifier);
+	_glcpp_parser_print_expanded_token_list (parser,
+						 macro->replacements);
+	_string_list_pop (parser->active);
+
+	return 0;
+}
+
+typedef enum function_status
+{
+	FUNCTION_STATUS_SUCCESS,
+	FUNCTION_NOT_A_FUNCTION,
+	FUNCTION_UNBALANCED_PARENTHESES
+} function_status_t;
+
+/* Find a set of function-like macro arguments by looking for a
+ * balanced set of parentheses. Upon return *node will be the last
+ * consumed node, such that further processing can continue with
+ * node->next.
+ *
+ * Return values:
+ *
+ *   FUNCTION_STATUS_SUCCESS:
+ *
+ *	Successfully parsed a set of function arguments.	
+ *
+ *   FUNCTION_NOT_A_FUNCTION:
+ *
+ *	Macro name not followed by a '('. This is not an error, but
+ *	simply that the macro name should be treated as a non-macro.
+ *
+ *   FUNCTION_UNBLANCED_PARENTHESES
+ *
+ *	Macro name is not followed by a balanced set of parentheses.
+ */
+static function_status_t
+_find_arguments (token_node_t **node_ret, argument_list_t **arguments)
+{
+	token_node_t *node = *node_ret, *last;
+	int paren_count;
+	int arg_count;
+
+	last = node;
+	node = node->next;
+
+	/* Ignore whitespace before first parenthesis. */
+	while (node && node->token->type == SPACE)
+		node = node->next;
+
+	if (node == NULL || node->token->type != '(')
+		return FUNCTION_NOT_A_FUNCTION;
+
+	paren_count = 0;
+	arg_count = 0;
+	do {
+		if (node->token->type == '(')
+		{
+			paren_count++;
+		}
+		else if (node->token->type == ')')
+		{
+			paren_count--;
+		}
+		else if (node->token->type == ',' &&
+			 paren_count == 1)
+		{
+			arg_count++;
+		}
+
+		last = node;
+		node = node->next;
+
+	} while (node && paren_count);
+
+	if (node && paren_count)
+		return FUNCTION_UNBALANCED_PARENTHESES;
+
+	*node_ret = last;
+
+	return FUNCTION_STATUS_SUCCESS;
+}
+
+/* Prints the expansion of *node (consuming further tokens from the
+ * list as necessary). Upon return *node will be the last consumed
+ * node, such that further processing can continue with node->next. */
+static void
+_glcpp_parser_print_expanded_function (glcpp_parser_t *parser,
+				       token_node_t **node_ret)
+{
+	macro_t *macro;
+	token_node_t *node;
+	const char *identifier;
+	argument_list_t *arguments;
+	function_status_t status;
+
+	node = *node_ret;
+	identifier = node->token->value.str;
+
+	macro = hash_table_find (parser->defines, identifier);
+
+	assert (macro->is_function);
+
+	status = _find_arguments (node_ret, &arguments);
+
+	switch (status) {
+	case FUNCTION_STATUS_SUCCESS:
+		break;
+	case FUNCTION_NOT_A_FUNCTION:
+		printf ("%s", identifier);
 		return;
+	case FUNCTION_UNBALANCED_PARENTHESES:
+		fprintf (stderr, "Error: Macro %s call has unbalanced parentheses\n",
+			 identifier);
+		exit (1);
 	}
 
 	_string_list_push (parser->active, identifier);
@@ -696,12 +827,15 @@
 					 token_list_t *list)
 {
 	token_node_t *node;
+	function_status_t function_status;
 
 	if (list == NULL)
 		return;
 
 	for (node = list->head; node; node = node->next) {
-		_glcpp_parser_print_expanded_token (parser, node->token);
+		if (_glcpp_parser_print_expanded_token (parser, node->token))
+			_glcpp_parser_print_expanded_function (parser, &node);
+
 		if (node->next)
 			printf (" ");
 	}