codegen.c


    1 #include <stdio.h>
    2 #include <assert.h>
    3 #include <stdlib.h>
    4 #include <string.h>
    5 #include "xcc.h"
    6 #include "AST.h"
    7 #include "type.h"
    8 #include "symbol.h"
    9 #include "codegen.h"
   10 
   11 static char *create_label(void);
   12 static char *get_opcode(enum AST_type ast_type, short flag);
   13 
   14 static char *create_label(void) {
   15 	static int num = 0;
   16 	char *label = emalloc(32);
   17 
   18 	snprintf(label, 32, "L%d", num++);
   19 	return label;
   20 }
   21 
   22 static char *get_opcode(enum AST_type ast_type, short flag) {
   23 	char *op = emalloc(32);
   24 
   25 	if (ast_type == AST_expression_lss)
   26 		if (flag == 0)
   27 			snprintf(op, 8, "setg");
   28 		else
   29 			snprintf(op, 8, "setl");
   30 	else if (ast_type == AST_expression_gtr)
   31 		if (flag == 0)
   32 			snprintf(op, 8, "setl");
   33 		else
   34 			snprintf(op, 8, "setg");
   35 	else if (ast_type == AST_expression_eq)
   36 		snprintf(op, 8, "sete");
   37 	else if (ast_type == AST_expression_neq)
   38 		snprintf(op, 8, "setne");
   39 	else if (ast_type == AST_expression_leq)
   40 		if (flag == 0)
   41 			snprintf(op, 8, "setge");
   42 		else
   43 			snprintf(op, 8, "setle");
   44 	else if (ast_type == AST_expression_geq)
   45 		if (flag == 0)
   46 			snprintf(op, 8, "setle");
   47 		else
   48 			snprintf(op, 8, "setge");
   49 	else if (ast_type == AST_expression_and)
   50 		snprintf(op, 8, "je");
   51 	else if (ast_type == AST_expression_or)
   52 		snprintf(op, 8, "jne");
   53 	else
   54 		assert(0);
   55 	return op;
   56 }
   57 
   58 void start_code(char *filename) {
   59 	fprintf(xcc_out, "	.file	\"%s\"\n", filename);
   60 }
   61 
   62 void end_code(void) {
   63 	int size;
   64 	struct Symbol *symbol;
   65 
   66 	for (symbol = symbol_table.global; symbol != NULL; symbol = symbol->next) {
   67 		size = symbol->type->size;
   68 		if (size > 0)
   69 			fprintf(xcc_out, "	.comm	_%s, %d\n", symbol->name, size);
   70 	}
   71 }
   72 
   73 char *codegen(struct AST *ast) {
   74 	int i;
   75 	int index;
   76 	char *op, *op1, *op2;
   77 	char *label1, *label2;
   78 	struct String *string;
   79 
   80 	switch (ast->ast_type) {
   81 	default:
   82 		for (i = 0; i < ast->num_child; i++)
   83 			codegen(ast->u.child[i]);
   84 		break;
   85 	case AST_function_definition:
   86 		for (string = ast->u2.func.string; string != NULL; string = string->next) {
   87 			fprintf(xcc_out, "%s:\n", string->label);
   88 			fprintf(xcc_out, "	.ascii \"%s\\0\"\n", string->data);
   89 		}
   90 		fprintf(xcc_out, ".globl _%s\n", ast->type->id);
   91 		fprintf(xcc_out, "_%s:\n", ast->type->id);
   92 		fprintf(xcc_out, "	pushl	%%ebp\n");
   93 		fprintf(xcc_out, "	movl	%%esp, %%ebp\n");
   94 		if (ast->u2.func.frame_size > 0)
   95 			fprintf(xcc_out, "	subl	$%d, %%esp\n", ast->u2.func.frame_size);
   96 		if (!strcmp(ast->type->id, "main"))
   97 			fprintf(xcc_out, "	call	___%s\n", ast->type->id);
   98 		codegen(ast->u.child[2]);
   99 		fprintf(xcc_out, "	leave\n");
  100 		fprintf(xcc_out, "	ret\n");
  101 		break;
  102 	case AST_statement_if:
  103 	case AST_statement_if_else:
  104 		op1 = codegen(ast->u.child[0]);
  105 		if (!strncmp(op1, "$", 1)) {
  106 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  107 			fprintf(xcc_out, "	cmpl	$0, %%eax\n");
  108 		} else if (!strncmp(op1, "popl", 4)) {
  109 			fprintf(xcc_out, "	addl	$4, %%esp\n");
  110 			fprintf(xcc_out, "	cmpl	$0, -4(%%esp)\n");
  111 		} else 
  112 			fprintf(xcc_out, "	cmpl	$0, %s\n", op1);
  113 		label1 = create_label();
  114 		fprintf(xcc_out, "	je	%s\n", label1);
  115 		codegen(ast->u.child[1]);
  116 		if (ast->ast_type == AST_statement_if_else) {
  117 			label2 = create_label();
  118 			fprintf(xcc_out, "	jmp	%s\n", label2);
  119 			fprintf(xcc_out, "%s:\n", label1);
  120 			codegen(ast->u.child[2]);
  121 			fprintf(xcc_out, "%s:\n", label2);
  122 			free(label2);
  123 		} else
  124 			fprintf(xcc_out, "%s:\n", label1);
  125 		free(label1);
  126 		free(op1);
  127 		break;
  128 	case AST_statement_while:
  129 		label1 = create_label();
  130 		label2 = create_label();
  131 		fprintf(xcc_out, "	jmp	%s\n", label2);
  132 		fprintf(xcc_out, "%s:\n", label1);
  133 		codegen(ast->u.child[1]);
  134 		fprintf(xcc_out, "%s:\n", label2);
  135 		op1 = codegen(ast->u.child[0]);
  136 		if (!strncmp(op1, "$", 1)) {
  137 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  138 			fprintf(xcc_out, "	cmpl	$0, %%eax\n");
  139 		} else if (!strncmp(op1, "popl", 4)) {
  140 			fprintf(xcc_out, "	addl	$4, %%esp\n");
  141 			fprintf(xcc_out, "	cmpl	$0, -4(%%esp)\n");
  142 		} else
  143 			fprintf(xcc_out, "	cmpl	$0, %s\n", op1);
  144 		fprintf(xcc_out, "	jne	%s\n", label1);
  145 		free(label1);
  146 		free(label2);
  147 		free(op1);
  148 		break;
  149 	case AST_statement_return:
  150 		op1 = codegen(ast->u.child[0]);
  151 		if (strncmp(op1, "popl", 4))
  152 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  153 		else
  154 			fprintf(xcc_out, "	popl	%%eax\n");
  155 		fprintf(xcc_out, "	leave\n");
  156 		fprintf(xcc_out, "	ret\n");
  157 		free(op1);
  158 		break;
  159 	case AST_statement_return_null:
  160 		fprintf(xcc_out, "	leave\n");
  161 		fprintf(xcc_out, "	ret\n");
  162 		break;
  163 	case AST_expression_id:
  164 		op1 = get_id_index(ast->u.child[0]->u.id, ast->parent);
  165 		return op1;
  166 	case AST_expression_int:
  167 	case AST_expression_char:
  168 		op1 = emalloc(32);
  169 		snprintf(op1, 32, "$%d", ast->u.value);
  170 		return op1;
  171 	case AST_expression_string:
  172 		op1 = emalloc(32);
  173 		snprintf(op1, 32, "$%s", get_string_label(ast->u.id, ast->parent));
  174 		return op1;
  175 	case AST_expression_assign:
  176 		op1 = get_id_index(ast->u.child[0]->type->id, ast->parent);
  177 		op2 = codegen(ast->u.child[1]);
  178 		if (!strncmp(op2, "$", 1))
  179 			fprintf(xcc_out, "	movl	%s, %s\n", op2, op1);
  180 		else if (!strncmp(op2, "popl", 4))
  181 			fprintf(xcc_out, "	popl	%s\n", op1);
  182 		else {
  183 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  184 			fprintf(xcc_out, "	movl	%%eax, %s\n", op1);
  185 		}
  186 		efree(op2);
  187 		return op1;
  188 	case AST_expression_lss:
  189 	case AST_expression_gtr:
  190 	case AST_expression_eq:
  191 	case AST_expression_neq:
  192 	case AST_expression_leq:
  193 	case AST_expression_geq:
  194 		op1 = codegen(ast->u.child[0]);
  195 		op2 = codegen(ast->u.child[1]);
  196 		if (!strncmp(op1, "popl", 4) && !strncmp(op2, "popl", 4)) {
  197 			fprintf(xcc_out, "	popl	%%eax\n");
  198 			fprintf(xcc_out, "	cmpl	(%%esp), %%eax\n");
  199 			op = get_opcode(ast->ast_type, 0);
  200 			fprintf(xcc_out, "	%s	%%al\n", op);
  201 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  202 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  203 		} else if (!strncmp(op1, "pop", 4) && !strncmp(op2, "$", 1)) {
  204 			fprintf(xcc_out, "	cmpl	%s, (%%esp)\n", op2);
  205 			op = get_opcode(ast->ast_type, 1);
  206 			fprintf(xcc_out, "	%s	%%al\n", op);
  207 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  208 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  209 		} else if (!strncmp(op1, "pop", 4)) {
  210 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  211 			fprintf(xcc_out, "	cmpl	(%%esp), %%eax\n");
  212 			op = get_opcode(ast->ast_type, 0);
  213 			fprintf(xcc_out, "	%s	%%al\n", op);
  214 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  215 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  216 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "popl", 4)) {
  217 			fprintf(xcc_out, "	cmpl	%s, (%%esp)\n", op1);
  218 			op = get_opcode(ast->ast_type, 0);
  219 			fprintf(xcc_out, "	%s	%%al\n", op);
  220 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  221 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  222 		} else if (!strncmp(op2, "popl", 4)) {
  223 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  224 			fprintf(xcc_out, "	cmpl	%%eax, (%%esp)\n");
  225 			op = get_opcode(ast->ast_type, 0);
  226 			fprintf(xcc_out, "	%s	%%al\n", op);
  227 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  228 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  229 		} else if (strncmp(op1, "$", 1) && strncmp(op2, "$", 1)) {
  230 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  231 			fprintf(xcc_out, "	cmpl	%%eax, %s\n", op2);
  232 			op = get_opcode(ast->ast_type, 0);
  233 			fprintf(xcc_out, "	%s	%%al\n", op);
  234 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  235 			fprintf(xcc_out, "	pushl	%%eax\n");
  236 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "$", 1)) {
  237 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  238 			fprintf(xcc_out, "	cmpl	%s, %%eax\n", op1);
  239 			op = get_opcode(ast->ast_type, 0);
  240 			fprintf(xcc_out, "	%s	%%al\n", op);
  241 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  242 			fprintf(xcc_out, "	pushl	%%eax\n");
  243 		} else if (strncmp(op1, "$", 1) && !strncmp(op2, "$", 1)) {
  244 			fprintf(xcc_out, "	cmpl	%s, %s\n", op2, op1);
  245 			op = get_opcode(ast->ast_type, 1);
  246 			fprintf(xcc_out, "	%s	%%al\n", op);
  247 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  248 			fprintf(xcc_out, "	pushl	%%eax\n");
  249 		} else {
  250 			fprintf(xcc_out, "	cmpl	%s, %s\n", op1, op2);
  251 			op = get_opcode(ast->ast_type, 0);
  252 			fprintf(xcc_out, "	%s	%%al\n", op);
  253 			fprintf(xcc_out, "	movzbl	%%al, %%eax\n");
  254 			fprintf(xcc_out, "	pushl	%%eax\n");
  255 		}
  256 		free(op);
  257 		free(op2);
  258 		snprintf(op1, 32, "popl");
  259 		return op1;
  260 	case AST_expression_and:
  261 	case AST_expression_or:
  262 		op = get_opcode(ast->ast_type, 0);
  263 		op1 = codegen(ast->u.child[0]);
  264 		if (!strncmp(op1, "$", 1)) {
  265 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  266 			fprintf(xcc_out, "	cmpl	$0, %%eax\n");
  267 		} else if (!strncmp(op1, "popl", 4)) {
  268 			fprintf(xcc_out, "	addl	$4, %%esp\n");
  269 			fprintf(xcc_out, "	cmpl	$0, -4(%%esp)\n");
  270 		} else
  271 			fprintf(xcc_out, "	cmpl	$0, %s\n", op1);
  272 		label1 = create_label();
  273 		fprintf(xcc_out, "	%s	%s\n", op, label1);	
  274 		op2 = codegen(ast->u.child[1]);
  275 		if (!strncmp(op2, "$", 1)) {
  276 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  277 			fprintf(xcc_out, "	cmpl	$0, %%eax\n");
  278 		} else if (!strncmp(op2, "popl", 4)) {
  279 			fprintf(xcc_out, "	addl	$4, %%esp\n");
  280 			fprintf(xcc_out, "	cmpl	$0, -4(%%esp)\n");
  281 		} else
  282 			fprintf(xcc_out, "	cmpl	$0, %s\n", op2);
  283 		fprintf(xcc_out, "	%s	%s\n", op, label1);
  284 		fprintf(xcc_out, "	subl	$4, %%esp\n");
  285 		if (ast->ast_type == AST_expression_and)
  286 			fprintf(xcc_out, "	movl	$1, (%%esp)\n");
  287 		else
  288 			fprintf(xcc_out, "	movl	$0, (%%esp)\n");
  289 		label2 = create_label();
  290 		fprintf(xcc_out, "	jmp	%s\n", label2);
  291 		fprintf(xcc_out, "%s:\n", label1);
  292 		fprintf(xcc_out, "	subl	$4, %%esp\n");
  293 		if (ast->ast_type == AST_expression_and)
  294 			fprintf(xcc_out, "	movl	$0, (%%esp)\n");
  295 		else
  296 			fprintf(xcc_out, "	movl	$1, (%%esp)\n");
  297 		fprintf(xcc_out, "%s:\n", label2);
  298 		free(label1);
  299 		free(label2);
  300 		free(op);
  301 		free(op2);
  302 		snprintf(op1, 32, "popl");
  303 		return op1;
  304 	case AST_expression_add:
  305 		op1 = codegen(ast->u.child[0]);
  306 		op2 = codegen(ast->u.child[1]);
  307 		if (!strncmp(op1, "popl", 4) && !strncmp(op2, "popl", 4)) {
  308 			fprintf(xcc_out, "	popl	%%eax\n");
  309 			fprintf(xcc_out, "	addl	%%eax, (%%esp)\n");
  310 		} else if (!strncmp(op1, "popl", 4) && !strncmp(op2, "$", 1))
  311 			fprintf(xcc_out, "	addl	%s, (%%esp)\n", op2);
  312 		else if (!strncmp(op1, "popl", 4)) {
  313 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  314 			fprintf(xcc_out, "	addl	%%eax, (%%esp)\n");
  315 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "popl", 4))
  316 			fprintf(xcc_out, "	addl	%s, (%%esp)\n", op1);
  317 		else if (!strncmp(op2, "popl", 4)) {
  318 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  319 			fprintf(xcc_out, "	addl	%%eax, (%%esp)\n");
  320 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "$", 1)) {
  321 			fprintf(xcc_out, "	subl	$4, %%esp\n");
  322 			fprintf(xcc_out, "	movl	%s, (%%esp)\n", op1);
  323 			fprintf(xcc_out, "	addl	%s, (%%esp)\n", op2);
  324 		} else if (!strncmp(op1, "$", 1)) {
  325 			fprintf(xcc_out, "	pushl	%s\n", op2);
  326 			fprintf(xcc_out, "	addl	%s, (%%esp)\n", op1);
  327 		} else if (!strncmp(op2, "$", 1)) {
  328 			fprintf(xcc_out, "	pushl	%s\n", op1);
  329 			fprintf(xcc_out, "	addl	%s, (%%esp)\n", op2);
  330 		} else {
  331 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  332 			fprintf(xcc_out, "	addl	%s, %%eax\n", op2);
  333 			fprintf(xcc_out, "	pushl	%%eax\n");
  334 		}
  335 		free(op2);
  336 		snprintf(op1, 32, "popl");
  337 		return op1;
  338 	case AST_expression_sub:
  339 		op1 = codegen(ast->u.child[0]);
  340 		op2 = codegen(ast->u.child[1]);
  341 		if (!strncmp(op1, "popl", 4) && !strncmp(op2, "popl", 4)) {
  342 			fprintf(xcc_out, "	popl	%%eax\n");
  343 			fprintf(xcc_out, "	subl	%%eax, (%%esp)\n");
  344 		} else if (!strncmp(op1, "popl", 4) && !strncmp(op2, "$", 1))
  345 			fprintf(xcc_out, "	subl	%s, (%%esp)\n", op2);
  346 		else if (!strncmp(op1, "popl", 4)) {
  347 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  348 			fprintf(xcc_out, "	subl	%%eax, (%%esp)\n");
  349 		} else if (!strncmp(op2, "popl", 4)) {
  350 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  351 			fprintf(xcc_out, "	subl	(%%esp), %%eax\n");
  352 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  353 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "$", 1)) {
  354 			fprintf(xcc_out, "	subl	$4, %%esp\n");
  355 			fprintf(xcc_out, "	movl	%s, (%%esp)\n", op1);
  356 			fprintf(xcc_out, "	subl	%s, (%%esp)\n", op2);
  357 		} else {
  358 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  359 			fprintf(xcc_out, "	subl	%s, %%eax\n", op2);
  360 			fprintf(xcc_out, "	pushl	%%eax\n");
  361 		}
  362 		free(op2);
  363 		snprintf(op1, 32, "popl");
  364 		return op1;
  365 	case AST_expression_mult:
  366 		op1 = codegen(ast->u.child[0]);
  367 		op2 = codegen(ast->u.child[1]);
  368 		if (!strncmp(op1, "popl", 4) && !strncmp(op2, "popl", 4)) {
  369 			fprintf(xcc_out, "	popl	%%eax\n");
  370 			fprintf(xcc_out, "	imull	(%%esp), %%eax\n");
  371 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  372 		} else if (!strncmp(op1, "popl", 4) && !strncmp(op2, "$", 1)) {
  373 			fprintf(xcc_out, "	imull	%s, (%%esp), %%eax\n", op2);
  374 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  375 		} else if (!strncmp(op1, "popl", 4)) {
  376 			fprintf(xcc_out, "	movl	%s, %%eax\n", op2);
  377 			fprintf(xcc_out, "	imull	(%%esp), %%eax\n");
  378 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  379 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "popl", 4)) {
  380 			fprintf(xcc_out, "	imull	%s, (%%esp), %%eax\n", op1);
  381 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  382 		} else if (!strncmp(op2, "popl", 4)) {
  383 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  384 			fprintf(xcc_out, "	imull	(%%esp), %%eax\n");
  385 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  386 		} else if (!strncmp(op1, "$", 1) && !strncmp(op2, "$", 1)) {
  387 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  388 			fprintf(xcc_out, "	imull	%s, %%eax\n", op2);
  389 			fprintf(xcc_out, "	pushl	%%eax\n");
  390 		} else if (!strncmp(op1, "$", 1)) {
  391 			fprintf(xcc_out, "	imull	%s, %s, %%eax\n", op1, op2);
  392 			fprintf(xcc_out, "	pushl	%%eax\n");
  393 		} else if (!strncmp(op2, "$", 1)) {
  394 			fprintf(xcc_out, "	imull	%s, %s, %%eax\n", op2, op1);
  395 			fprintf(xcc_out, "	pushl	%%eax\n");
  396 		} else {
  397 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  398 			fprintf(xcc_out, "	imull	%s, %%eax\n", op2);
  399 			fprintf(xcc_out, "	pushl	%%eax\n");
  400 		}
  401 		free(op2);
  402 		snprintf(op1, 32, "popl");
  403 		return op1;
  404 	case AST_expression_div:
  405 		op1 = codegen(ast->u.child[0]);
  406 		op2 = codegen(ast->u.child[1]);
  407 		fprintf(xcc_out, "	movl	$0, %%edx\n");
  408 		if (!strncmp(op1, "popl", 4) && !strncmp(op2, "popl", 4)) {
  409 			fprintf(xcc_out, "	movl	-4(%%esp), %%eax\n");
  410 			fprintf(xcc_out, "	idivl	(%%esp)\n");
  411 			fprintf(xcc_out, "	movl	%%eax, -4(%%esp)\n");
  412 			fprintf(xcc_out, "	addl	$4, %%esp\n");
  413 		} else if (!strncmp(op1, "popl", 4) && !strncmp(op2, "$", 1)) {
  414 			fprintf(xcc_out, "	movl	(%%esp), %%eax\n");
  415 			fprintf(xcc_out, "	movl	%s, %%ecx\n", op2);
  416 			fprintf(xcc_out, "	idivl	%%ecx\n");
  417 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  418 		} else if (!strncmp(op1, "popl", 4)) {
  419 			fprintf(xcc_out, "	movl	(%%esp), %%eax\n");
  420 			fprintf(xcc_out, "	idivl	%s\n", op2);
  421 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  422 		} else if (!strncmp(op2, "popl", 4)) {
  423 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  424 			fprintf(xcc_out, "	idivl	(%%esp)\n");
  425 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  426 		} else if (!strncmp(op2, "$", 1)) {
  427 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  428 			fprintf(xcc_out, "	movl	%s, %%ecx\n", op2);
  429 			fprintf(xcc_out, "	idivl	%%ecx\n");
  430 			fprintf(xcc_out, "	pushl	%%eax\n");
  431 		} else {
  432 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  433 			fprintf(xcc_out, "	idivl	%s\n", op2);
  434 			fprintf(xcc_out, "	pushl	%%eax\n");
  435 		}
  436 		free(op2);
  437 		snprintf(op1, 32, "popl");
  438 		return op1;
  439 	case AST_expression_mod:
  440 		op1 = codegen(ast->u.child[0]);
  441 		op2 = codegen(ast->u.child[1]);
  442 		fprintf(xcc_out, "	movl	$0, %%edx\n");
  443 		if (!strncmp(op1, "popl", 4) && !strncmp(op2, "popl", 4)) {
  444 			fprintf(xcc_out, "	movl	-4(%%esp), %%eax\n");
  445 			fprintf(xcc_out, "	idivl	(%%esp)\n");
  446 			fprintf(xcc_out, "	movl	%%edx, -4(%%esp)\n");
  447 			fprintf(xcc_out, "	addl	$4, %%esp\n");
  448 		} else if (!strncmp(op1, "popl", 4) && !strncmp(op2, "$", 1)) {
  449 			fprintf(xcc_out, "	movl	(%%esp), %%eax\n");
  450 			fprintf(xcc_out, "	movl	%s, %%ecx\n", op2);
  451 			fprintf(xcc_out, "	idivl	%%ecx\n");
  452 			fprintf(xcc_out, "	movl	%%edx, (%%esp)\n");
  453 		} else if (!strncmp(op1, "popl", 4)) {
  454 			fprintf(xcc_out, "	movl	(%%esp), %%eax\n");
  455 			fprintf(xcc_out, "	idivl	%s\n", op2);
  456 			fprintf(xcc_out, "	movl	%%edx, (%%esp)\n");
  457 		} else if (!strncmp(op2, "popl", 4)) {
  458 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  459 			fprintf(xcc_out, "	idivl	(%%esp)\n");
  460 			fprintf(xcc_out, "	movl	%%edx, (%%esp)\n");
  461 		} else if (!strncmp(op2, "$", 1)) {
  462 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  463 			fprintf(xcc_out, "	movl	%s, %%ecx\n", op2);
  464 			fprintf(xcc_out, "	idivl	%%ecx\n");
  465 			fprintf(xcc_out, "	pushl	%%edx\n");
  466 		} else {
  467 			fprintf(xcc_out, "	movl	%s, %%eax\n", op1);
  468 			fprintf(xcc_out, "	idivl	%s\n", op2);
  469 			fprintf(xcc_out, "	pushl	%%edx\n");
  470 		}
  471 		free(op2);
  472 		snprintf(op1, 32, "popl");
  473 		return op1;
  474 	case AST_expression_func:
  475 		codegen(ast->u.child[1]);
  476 		fprintf(xcc_out, "	call	_%s\n", ast->type->id);
  477 		op1 = emalloc(32);
  478 		index = ast->u.child[1]->u2.arg_size;
  479 		if (ast->type->u.t_prim.ptype != PRIM_TYPE_VOID) {
  480 			if (index != 4) {
  481 				snprintf(op1, 32, "$%d", index - 4);
  482 				fprintf(xcc_out, "	addl	%s, %%esp\n", op1);
  483 			}
  484 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  485 			snprintf(op1, 32, "popl");
  486 			return op1;
  487 		} else {
  488 			snprintf(op1, 32, "$%d", index);
  489 			fprintf(xcc_out, "	addl	%s, %%esp\n", op1);
  490 			free(op1);
  491 		}
  492 		break;
  493 	case AST_expression_func_null:
  494 		fprintf(xcc_out, "	call	_%s\n", ast->type->id);
  495 		if (ast->type->u.t_prim.ptype != PRIM_TYPE_VOID) {
  496 			op1 = emalloc(32);
  497 			fprintf(xcc_out, "	movl	%%eax, (%%esp)\n");
  498 			snprintf(op1, 32, "popl");
  499 			return op1;
  500 		}
  501 		break;
  502 	case AST_argument_expression_list_single:
  503 	case AST_argument_expression_list_pair:
  504 		if (ast->ast_type == AST_argument_expression_list_single)
  505 			op1 = codegen(ast->u.child[0]);
  506 		else
  507 			op1 = codegen(ast->u.child[1]);
  508 		if (!strncmp(op1, "$", 1)) {
  509 			fprintf(xcc_out, "	subl	$4, %%esp\n");
  510 			fprintf(xcc_out, "	movl	%s, (%%esp)\n", op1);
  511 		} else if (strncmp(op1, "popl", 4))
  512 			fprintf(xcc_out, "	pushl	%s\n", op1);
  513 		if (ast->ast_type == AST_argument_expression_list_pair)
  514 			codegen(ast->u.child[0]);
  515 		free(op1);
  516 		break;
  517 	}
  518 	return NULL;
  519 }