1 /*
2  * Copyright (c) 2006 - 2010, Nils R. Weller
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Parses gas inline assembly language statements and converts them to NASM
28  * code
29  */
30 #include "inlineasm.h"
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #include <errno.h>
38 #include "defs.h"
39 #include "token.h"
40 #include "expr.h"
41 #include "backend.h"
42 #include "error.h"
43 #include "x86_emit_nasm.h"
44 #include "x86_emit_gas.h"
45 #include "x86_gen.h"
46 #include "n_libc.h"
47 
48 
49 static int		lineno;
50 static struct token	*asm_tok;
51 
52 /*
53  * XXX the store_char() stuff bothers me, this adhoc interface should've been
54  * trashed long ago
55  */
56 
57 static int
get_char(char ** code)58 get_char(char **code) {
59 	int	ret;
60 
61 	if (**code == 0) {
62 		return EOF;
63 	}
64 	ret = (unsigned char)**code;
65 	++*code;
66 	return ret;
67 }
68 
69 static void
unget_char(int ch,char ** code)70 unget_char(int ch, char **code) {
71 	(void) ch;
72 	--*code;
73 }
74 
75 #if 0
76 struct gas_token {
77 	int			type;
78 #define GAS_SEPARATOR	1001
79 #define GAS_DOTSTRING	1002
80 #define GAS_STRING	1003
81 #define GAS_DOLLAR	1004
82 #define GAS_OCTAL	1020
83 #define GAS_HEXA	1021
84 #define GAS_DECIMAL	1022
85 #define GAS_NUMBER(x) (x == GAS_OCTAL || x == GAS_HEXA || x == GAS_DECIMAL)
86 	int			lineno;
87 	int			idata;
88 	void			*data;
89 	char			*ascii;
90 	struct gas_token	*next;
91 };
92 #endif
93 #define ALLOCATED_TOKEN(type) \
94 	(type == GAS_DOTIDENT || type == GAS_IDENT || \
95 	 type == GAS_OCTAL || type == GAS_HEXA || type == GAS_DECIMAL)
96 
97 static struct gas_token *
make_gas_token(int type,void * data)98 make_gas_token(int type, void *data) {
99 	struct gas_token	*ret;
100 	static struct gas_token	nulltok;
101 
102 	ret = n_xmalloc(sizeof *ret);
103 	*ret = nulltok;
104 	ret->type = type;
105 	ret->data = data;
106 	ret->lineno = lineno;
107 	switch (ret->type) {
108 	case TOK_PAREN_OPEN:
109 		ret->ascii = "(";
110 		break;
111 	case TOK_PAREN_CLOSE:
112 		ret->ascii = ")";
113 		break;
114 	case GAS_IDENT:
115 	case GAS_DOTIDENT:
116 	case GAS_OCTAL:
117 	case GAS_HEXA:
118 	case GAS_DECIMAL:
119 	default:
120 		ret->ascii = ret->data;
121 		break;
122 	}
123 
124 	return ret;
125 }
126 
127 
128 static int	gas_errors;
129 
130 static void
gas_errorfl(struct gas_token * gt,const char * fmt,...)131 gas_errorfl(struct gas_token *gt, const char *fmt, ...) {
132 	va_list	va;
133 
134 	++gas_errors;
135 	++errors;
136 	fprintf(stderr, "%s:%d+%d: ", asm_tok->file, asm_tok->line, gt->lineno);
137 	va_start(va, fmt);
138 	vfprintf(stderr, fmt, va);
139 	va_end(va);
140 	fputc('\n', stderr);
141 	print_source_line(asm_tok->line_ptr, asm_tok->tok_ptr, asm_tok->ascii,
142 		1);
143 }
144 
145 static struct gas_token *
get_string(char ** code)146 get_string(char **code) {
147 	char	*buf = NULL;
148 	int	ch;
149 
150 	store_char(NULL, 0);
151 	while ((ch = get_char(code)) != EOF) {
152 		if (ch == '"') {
153 			break;
154 		}
155 		store_char(&buf, ch);
156 	}
157 	store_char(&buf, 0);
158 	return make_gas_token(GAS_STRING, buf);
159 }
160 
161 static struct gas_token *
get_ident(int firstch,char ** code)162 get_ident(int firstch, char **code) {
163 	char	*buf = NULL;
164 	int	toktype;
165 	int	ch;
166 
167 	store_char(NULL, 0);
168 
169 	if (firstch == '.') {
170 		toktype = GAS_DOTIDENT;
171 	} else {
172 		toktype = GAS_IDENT;
173 		store_char(&buf, firstch);
174 	}
175 
176 	while ((ch = get_char(code)) != EOF) {
177 		if (isalnum(ch) || ch == '_') {
178 			store_char(&buf, ch);
179 		} else {
180 			unget_char(ch, code);
181 			break;
182 		}
183 	}
184 	store_char(&buf, 0);
185 	return make_gas_token(toktype, buf);
186 }
187 
188 
189 static struct gas_token *
get_number(int firstch,char ** code,int sign)190 get_number(int firstch, char **code, int sign) {
191 	char			*buf = NULL;
192 	struct gas_token	*ret;
193 	unsigned long		*val;
194 	int			hexa = 0;
195 	int			octal = 0;
196 	int			ch;
197 
198 	store_char(NULL, 0);
199 	store_char(&buf, firstch);
200 	if (firstch == '0') {
201 		/* May be hexadecimal */
202 		if ((ch = get_char(code)) == EOF) {
203 			goto out;
204 		}
205 		if (ch == 'x') {
206 			store_char(&buf, 'x');
207 			hexa = 1;
208 		} else if (!isdigit(ch)) {
209 			store_char(&buf, '0');
210 			unget_char(ch, code);
211 			goto out;
212 		} else {
213 			octal = 1;
214 			store_char(&buf, ch);
215 		}
216 	}
217 
218 	while ((ch = get_char(code)) != EOF) {
219 		ch = tolower(ch);
220 		if (isdigit(ch)
221 			|| (hexa && ch && strchr("abcdef", ch))) {
222 			store_char(&buf, ch);
223 #if 0
224 		} else if ((ch == 'f' || ch == 'b') && !hexa) {
225 			/*
226 			 * 02/28/09: This isn't really a number but a
227 			 * numeric label like ``1f'' or ``1b'';
228 			 *
229 			 *   jne 1f
230 			 *   1:
231 			 */
232 			store_char(&buf, ch);
233 			if (ch == 'f') {
234 				return make_gas_token(GAS_FORWARD_LABEL, buf);
235 			} else {
236 				return make_gas_token(GAS_BACKWARD_LABEL, buf);
237 			}
238 #endif
239 		} else {
240 			unget_char(ch, code);
241 			break;
242 		}
243 	}
244 out:
245 	store_char(&buf, 0);
246 	val = n_xmalloc(sizeof *val);
247 	if (octal) {
248 		sscanf(buf, "%lo", val);
249 		ret = make_gas_token(GAS_OCTAL, buf);
250 	} else if (hexa) {
251 		sscanf(buf, "%lx", val);
252 		ret = make_gas_token(GAS_HEXA, buf);
253 	} else {
254 		sscanf(buf, "%ld", val);
255 		ret = make_gas_token(GAS_DECIMAL, buf);
256 	}
257 	ret->data2 = val;
258 	if (sign) {
259 		ret->idata = 1;
260 	}
261 	return ret;
262 }
263 
264 
265 
266 static void
append_gas_list(struct gas_token ** dest,struct gas_token ** dest_tail,struct gas_token * src)267 append_gas_list(
268 	struct gas_token **dest,
269 	struct gas_token **dest_tail,
270 	struct gas_token *src) {
271 	if (*dest == NULL) {
272 		*dest = *dest_tail = src;
273 	} else {
274 		(*dest_tail)->next = src;
275 		*dest_tail = (*dest_tail)->next;
276 	}
277 }
278 
279 static void
free_gas_token(struct gas_token * t)280 free_gas_token(struct gas_token *t) {
281 	if (t == NULL) return;
282 	if (t->data != NULL) {
283 		if (ALLOCATED_TOKEN(t->type)) {
284 			free(t->data);
285 		}
286 	}
287 	free(t);
288 }
289 
290 static void
free_gas_token_list(struct gas_token * t)291 free_gas_token_list(struct gas_token *t) {
292 	while (t != NULL) {
293 		struct gas_token	*next = t->next;
294 		free_gas_token(t);
295 		t = next;
296 	}
297 }
298 
299 static struct gas_token *
tokenize_gas_code(char * code)300 tokenize_gas_code(char *code) {
301 	int			ch;
302 	struct gas_token	*gt;
303 	struct gas_token	*glist = NULL;
304 	struct gas_token	*glist_tail = NULL;
305 	struct gas_token	dummytok;
306 
307 	lineno = 0;
308 
309 	while ((ch = get_char(&code)) != EOF) {
310 		gt = NULL;
311 		switch (ch) {
312 		case '\t':
313 		case ' ':
314 		case '\n':
315 			if (ch == '\n') {
316 				++lineno;
317 				gt = make_gas_token(GAS_SEPARATOR, NULL);
318 			}
319 			break;
320 		case ';':
321 			gt = make_gas_token(GAS_SEPARATOR, NULL);
322 			break;
323 		case '(':
324 			gt = make_gas_token(TOK_PAREN_OPEN, NULL);
325 			break;
326 		case ')':
327 			gt = make_gas_token(TOK_PAREN_CLOSE, NULL);
328 			break;
329 		case '-':
330 			while ((ch = get_char(&code)) != EOF
331 				&& isspace(ch))
332 				;
333 
334 			if (ch == EOF || !isdigit(ch)) {
335 				dummytok.lineno = lineno;
336 				gas_errorfl(&dummytok,
337 					"Parse error at `%c' (%d)",
338 					ch == EOF? '-': ch, __LINE__);
339 				free_gas_token_list(glist);
340 				return NULL;
341 			}
342 
343 			gt = get_number(ch, &code, 1);
344 			break;
345 		case ',':
346 			gt = make_gas_token(TOK_OP_COMMA, NULL);
347 			break;
348 		case '"':
349 			gt = get_string(&code);
350 			break;
351 		case ':':
352 			gt = make_gas_token(TOK_OP_AMB_COND2, ":");
353 			break;
354 		case '$':
355 			gt = make_gas_token(GAS_DOLLAR, "$");
356 			break;
357 		case '%':
358 			gt = make_gas_token(TOK_OP_MOD, "%");
359 			break;
360 		case '.':
361 #if 0
362 			if ((ch = get_char(&code)) == EOF
363 				|| !isalnum((unsigned char)ch)) {
364 				dummytok.lineno = lineno;
365 				gas_errorfl(&dummytok,
366 					"Parse error at `%c' (%d)",
367 					ch, __LINE__);
368 				free_gas_token_list(glist);
369 				return NULL;
370 			}
371 #endif
372 			gt = get_ident(ch, &code);
373 			break;
374 		default:
375 			if (isdigit((unsigned char)ch)) {
376 				gt = get_number(ch, &code, 0);
377 			} else if (isalpha((unsigned char)ch) || ch == '_') {
378 				gt = get_ident(ch, &code);
379 			} else {
380 				dummytok.lineno = lineno;
381 				gas_errorfl(&dummytok,
382 					"Parse error at `%c' (%d)",
383 					ch, __LINE__);
384 				free_gas_token_list(glist);
385 				return NULL;
386 			}
387 		}
388 		if (gt != NULL) {
389 			append_gas_list(&glist, &glist_tail, gt);
390 		}
391 	}
392 
393 #if 0
394 	printf("tokens:\n");
395 	for (gt = glist; gt != NULL; gt = gt->next) {
396 		printf("\t%d\n", gt->type);
397 	}
398 #endif
399 	return glist;
400 }
401 
402 #if 0
403 struct gas_operand {
404 #define ITEM_REG	1
405 #define ITEM_NUMBER	2
406 #define ITEM_VARIABLE	3
407 #define ITEM_IO		4
408 	int	addr_mode;
409 #define ADDR_ABSOLUTE	1
410 #define ADDR_INDIRECT	2
411 #define ADDR_SCALED	3
412 #define ADDR_DISPLACE	4
413 #define ADDR_SCALED_DISPLACE	5
414 	void	*items[4];
415 	int	item_types[4];
416 };
417 #endif
418 
419 static int
next_gas_token(struct gas_token ** tok)420 next_gas_token(struct gas_token **tok) {
421 	if ((*tok)->next == NULL) {
422 		struct gas_token	dummy;
423 		dummy.lineno = lineno;
424 		gas_errorfl(&dummy, "Unexpected end of assembler statement");
425 		return -1;
426 	}
427 	*tok = (*tok)->next;
428 	return 0;
429 }
430 
431 static int
is_number(const char * str)432 is_number(const char *str) {
433 	for (; isdigit((unsigned char)*str); ++str);
434 		;
435 	return *str == 0;
436 }
437 
438 static struct inline_asm_io *
get_operand_by_idx(struct inline_asm_stmt * st,struct gas_token * t,int idx,int * curitem_type)439 get_operand_by_idx(
440 	struct inline_asm_stmt *st,
441 	struct gas_token *t,
442 	int idx,
443 	int *curitem_type) {
444 
445 	struct inline_asm_io	*io;
446 	int			n_ios = st->n_inputs + st->n_outputs;
447 
448 	if (t != NULL) {
449 		idx = (int)*(unsigned long *)t->data2;
450 	}
451 
452 	if (idx >= n_ios) {
453 		gas_errorfl(t, "I/O operand %d does "
454 			"not exist, highest is %lu "
455 			"(first one is %0!)", idx, n_ios);
456 		return NULL;
457 	}
458 	++idx;
459 	if ((st->output != NULL
460 		&& idx > st->n_outputs)
461 		|| (st->output == NULL)) {
462 		/* Must be input */
463 		idx -= st->n_outputs;
464 		if (curitem_type != NULL) {
465 			*curitem_type = ITEM_INPUT;
466 		}
467 		io = st->input;
468 	} else {
469 		/* Output */
470 		if (curitem_type != NULL) {
471 			*curitem_type = ITEM_OUTPUT;
472 		}
473 		io = st->output;
474 	}
475 	while (--idx > 0) {
476 		io = io->next;
477 	}
478 	return io;
479 }
480 
481 static char *
get_constraint_by_idx(struct inline_asm_stmt * data,int idx)482 get_constraint_by_idx(struct inline_asm_stmt *data, int idx) {
483 	int			i;
484 	struct inline_asm_io	*io = data->output;
485 	int			input_done = 0;
486 
487 	for (i = 0; i < idx; ++i) {
488 		if (io == NULL) {
489 			if (input_done) {
490 				return NULL;
491 			} else {
492 				io = data->input;
493 			}
494 		}
495 		if (io == NULL) {
496 			return NULL;
497 		}
498 		io = io->next;
499 	}
500 	if (io != NULL) {
501 		return io->constraints;
502 	}
503 	return NULL;
504 }
505 
506 /*
507  * Parses an operand to an instruction. This resembles a state machine,
508  * which is why it is hard to read. Basically, it just always reads either
509  * a parentheses or an ``item'' (a register, number or variable.)
510  * Parentheses may dictate some sort of indirect addressing mode. The items
511  * and their types are stored in the items and item_types arrays in the
512  * order in which they appear;
513  * -0x20(%eax)  ->  -0x20=items[0], %eax=items[1]
514  * 0x80(%eax,%ebx,0x4) ->   0x80=items[0], %eax=items[1], ....
515  */
516 static struct gas_operand *
parse_operand(struct gas_token ** tok,struct inline_asm_stmt * stmt)517 parse_operand(struct gas_token **tok, struct inline_asm_stmt *stmt) {
518 	struct gas_token		*t;
519 	struct gas_operand		*ret;
520 	static struct gas_operand	nullop;
521 	void				**curitem;
522 	int				*curitem_type;
523 	int				index = 0;
524 
525 	ret = n_xmalloc(sizeof *ret);
526 	*ret = nullop;
527 	curitem = &ret->items[0];
528 	curitem_type = &ret->item_types[0];
529 
530 	for (t = *tok; t != NULL; t = t->next) {
531 		if (t->type == GAS_DOLLAR) {
532 			/* Should be immediate - $1234 */
533 			if (next_gas_token(&t) != 0) {
534 				return NULL;
535 			}
536 			if (t->type == GAS_IDENT) {
537 				*curitem_type = ITEM_VARIABLE;
538 				*curitem = t;
539 			} else if (GAS_NUMBER(t->type)) {
540 				*curitem_type = ITEM_NUMBER;
541 				*curitem = t;
542 			} else {
543 				gas_errorfl(t, "Parse error at `%s' (%d)",
544 					t->ascii, __LINE__);
545 				return NULL;
546 			}
547 		} else if (GAS_NUMBER(t->type)) {
548 			if (t->next
549 				&& t->next->type == GAS_IDENT
550 				&& (strcmp(t->next->data, "b") == 0
551 					|| strcmp(t->next->data, "f") == 0)) {
552 				*curitem_type = ITEM_LABEL;
553 				*curitem = /* XXX */
554 					backend->get_inlineasm_label(t->data);
555 				t = t->next;
556 			} else {
557 				*curitem_type = ITEM_NUMBER;
558 				*curitem = t;
559 				if (ret->addr_mode == 0) {
560 					ret->addr_mode = ADDR_ABSOLUTE;
561 				} else {
562 					gas_errorfl(t,
563 						"Parse error at `%s' (%d)",
564 						t->ascii, __LINE__);
565 					return NULL;
566 				}
567 			}
568 			++index;
569 			curitem = &ret->items[index];
570 			curitem_type = &ret->item_types[index];
571 		} else if (t->type == GAS_IDENT) {
572 			/*
573 			 * XXX can this possibly be right, and made work with
574 			 * NASM?!?
575 			 */
576 			*curitem_type = ITEM_VARIABLE;
577 			*curitem = t;
578 			if (ret->addr_mode == 0) {
579 				ret->addr_mode = ADDR_INDIRECT;
580 			} else {
581 				gas_errorfl(t, "Parse error at `%s' (%d)",
582 					t->ascii, __LINE__);
583 				return NULL;
584 			}
585 #if 0
586 		} else if (t->type == GAS_FORWARD_LABEL
587 			|| t->type == GAS_BACKWARD_LABEL) {
588 			*curitem_type = ITEM_FW_BW;
589 			if (ret->addr_mode == 0) {
590 				ret->addr_mode = ADDR_
591 #endif
592 		} else if (t->type == TOK_OP_MOD) {
593 			if (next_gas_token(&t) != 0) {
594 				return NULL;
595 			}
596 			if (t->type == TOK_OP_MOD) {
597 				/* Should be %%reg */
598 				if (next_gas_token(&t) != 0) {
599 					return NULL;
600 				}
601 				if (t->type != GAS_IDENT) {
602 					gas_errorfl(t,
603 						"Parse error at `%s' (%d)",
604 						t->ascii, __LINE__);
605 					return NULL;
606 				} else if (!stmt->extended) {
607 					gas_errorfl(t, "Second %% in %%%%reg "
608 						"is only allowed for "
609 						"extended asm statements "
610 						"(use %reg instead)");
611 					return NULL;
612 				}
613 				*curitem_type = ITEM_REG;
614 				*curitem = t;
615 			} else if (GAS_NUMBER(t->type)) {
616 				struct inline_asm_io	*io;
617 
618 				/* i/o operand */
619 				if (!stmt->extended) {
620 					gas_errorfl(t, "`%%number' is only "
621 						"allowed in extended asm "
622 						"statements");
623 					return NULL;
624 				}
625 				io = get_operand_by_idx(stmt, t, 0,
626 					curitem_type);
627 
628 				if (io == NULL) {
629 					return NULL;
630 				}
631 				*curitem = io;
632 				++index;
633 				curitem = &ret->items[index];
634 				curitem_type = &ret->item_types[index];
635 			} else if (t->type == GAS_IDENT) {
636 				if (stmt->extended) {
637 					if ((t->ascii[0] == 'h'
638 						|| t->ascii[0] == 'b'
639 						|| t->ascii[0] == 'w')
640 						&& is_number(t->ascii+1)) {
641 						char	*p;
642 						long	rc;
643 						struct inline_asm_io	*io;
644 
645 						errno = 0;
646 						rc = strtol(t->ascii+1, &p, 0);
647 						if (errno
648 							|| rc == LONG_MIN
649 							|| rc == LONG_MAX
650 							|| *p) {
651 							gas_errorfl(t,
652 					"Parse error at `%s' (%d)",
653 							t->ascii, __LINE__);
654 							return NULL;
655 						}
656 						io = get_operand_by_idx(stmt,
657 							NULL, rc, curitem_type);
658 						if (io == NULL) {
659 							return NULL;
660 						}
661 
662 						*curitem = io;
663 						if (t->ascii[0] == 'w') {
664 							*curitem_type = ITEM_SUBREG_W;
665 						} else {
666 							*curitem_type =
667 								t->ascii[0] == 'b'?
668 								ITEM_SUBREG_B
669 									: ITEM_SUBREG_H;
670 						}
671 					} else {
672 						gas_errorfl(t, "%%reg isn't "
673 		"allowed in extended asm statements (use %%%%reg instead)");
674 						return NULL;
675 					}
676 				} else {
677 					*curitem_type = ITEM_REG;
678 					*curitem = t;
679 				}
680 				++index;
681 				curitem = &ret->items[index];
682 				curitem_type = &ret->item_types[index];
683 			} else {
684 				gas_errorfl(t, "Parse error at `%s' (%d)",
685 					t->ascii, __LINE__);
686 				return NULL;
687 			}
688 		} else if (t->type == TOK_PAREN_OPEN) {
689 			if (t == *tok) {
690 				/* Scaled or indirect addressing */
691 				ret->addr_mode = ADDR_INDIRECT;
692 			} else if (ret->item_types[0] != 0) {
693 				/*
694 				 * Displacement - $123(stuff)
695 				 */
696 				if (ret->item_types[0] != ITEM_NUMBER) {
697 					gas_errorfl(t, "Invalid "
698 						"displacement");
699 					return NULL;
700 				}
701 				ret->addr_mode = ADDR_DISPLACE;
702 				curitem = &ret->items[1];
703 				curitem_type = &ret->item_types[1];
704 				++index;
705 			} else {
706 				gas_errorfl(t, "Parse error at `%s' (%d)",
707 					t->ascii, __LINE__);
708 				return NULL;
709 			}
710 		} else if (t->type == TOK_PAREN_CLOSE) {
711 			if (ret->addr_mode != ADDR_INDIRECT
712 				&& ret->addr_mode != ADDR_DISPLACE
713 				&& ret->addr_mode != ADDR_SCALED
714 				&& ret->addr_mode != ADDR_SCALED_DISPLACE) {
715 				gas_errorfl(t, "Parse error at `%s' (%d)",
716 					t->ascii, __LINE__);
717 				return NULL;
718 			}
719 			if (t->next) {
720 				if (t->next->type == TOK_OP_COMMA
721 					|| t->next->type == GAS_SEPARATOR) {
722 					t = t->next;
723 					break;
724 				} else {
725 					/* XXX wut to do?! */
726 				}
727 			} else {
728 				t = t->next;
729 				break;
730 			}
731 		} else if (t->type == TOK_OP_COMMA) {
732 			if (ret->addr_mode != ADDR_INDIRECT
733 				&& ret->addr_mode != ADDR_SCALED
734 				&& ret->addr_mode != ADDR_DISPLACE
735 				&& ret->addr_mode != ADDR_SCALED_DISPLACE) {
736 				/* ok, operand ends here */
737 				break;
738 			} else if (ret->addr_mode == ADDR_SCALED
739 				|| ret->addr_mode == ADDR_SCALED_DISPLACE) {
740 				int	max = ret->addr_mode == ADDR_SCALED?
741 					2: 3;
742 				if (index >= max) {
743 					gas_errorfl(t, "Too many operands"
744 						" for scaled addressing");
745 				} else {
746 					curitem = &ret->items[++index];
747 					curitem_type = &ret->item_types[index];
748 				}
749 			} else {
750 				if (ret->addr_mode == ADDR_DISPLACE) {
751 					/* 0x123(foo,bar,baz) */
752 					ret->addr_mode = ADDR_SCALED_DISPLACE;
753 				} else {
754 					ret->addr_mode = ADDR_SCALED;
755 				}
756 				++index;
757 				curitem = &ret->items[index];
758 				curitem_type = &ret->item_types[index];
759 			}
760 		} else if (t->type == GAS_SEPARATOR) {
761 			/* Instruction ends here */
762 			break;
763 		} else {
764 			gas_errorfl(t, "Parse error at `%s' (%d)",
765 				t->ascii, __LINE__);
766 			return NULL;
767 		}
768 	}
769 	*tok = t;
770 	return ret;
771 }
772 
773 #if 0
774 static void
775 free_gas_operand(struct gas_operand *t) {
776 	(void)t;
777 }
778 #endif
779 
780 
781 static void
782 store_plusminus_num(FILE *out, void *item) {
783 	struct gas_token	*nt;
784 
785 	x_fputc(' ', out);
786 	nt = item;
787 	if (!nt->idata) {
788 		/* Not signed */
789 		x_fputc('+', out);
790 	} else {
791 		x_fputc('-', out);
792 	}
793 	x_fputc(' ', out);
794 
795 	print_item_nasm(out, item, ITEM_NUMBER, 0);
796 }
797 
798 static void
799 print_operand_nasm(FILE *out, struct gas_operand *op, int postfix) {
800 	char	*p;
801 	int	i;
802 
803 	if (op->addr_mode != 0 && postfix) {
804 		if (postfix == 'b') {
805 			p = "byte";
806 		} else if (postfix == 'w') {
807 			p = "word";
808 		} else if (postfix == 'l') {
809 			p = "dword";
810 		} else if (postfix == 'q') {
811 			p = "qword";
812 		} else if (postfix == 't') {
813 			p = "tword";
814 		} else {
815 			abort();
816 		}
817 		x_fprintf(out, "%s ", p);
818 	}
819 
820 	switch (op->addr_mode) {
821 	case 0:
822 		print_item_nasm(out, op->items[0], op->item_types[0], postfix);
823 		break;
824 	case ADDR_INDIRECT:
825 		x_fputc('[', out);
826 		print_item_nasm(out, op->items[0], op->item_types[0], postfix);
827 		x_fputc(']', out);
828 		break;
829 	case ADDR_SCALED:
830 	case ADDR_SCALED_DISPLACE:
831 		if (op->addr_mode == ADDR_SCALED) {
832 			i = 0;
833 		} else {
834 			i = 1;
835 		}
836 
837 		x_fputc('[', out);
838 		print_item_nasm(out, op->items[i], op->item_types[i], postfix);
839 		x_fprintf(out, " + ");
840 		++i;
841 		print_item_nasm(out, op->items[i], op->item_types[i], postfix);
842 
843 		++i;
844 		if (op->item_types[i] != 0) {
845 			x_fprintf(out, " * ");
846 			print_item_nasm(out, op->items[i],
847 				op->item_types[i], postfix);
848 		}
849 		if (op->addr_mode == ADDR_SCALED_DISPLACE) {
850 			store_plusminus_num(out, op->items[0]);
851 		}
852 		x_fputc(']', out);
853 		break;
854 	case ADDR_DISPLACE:
855 		x_fputc('[', out);
856 		print_item_nasm(out, op->items[1], op->item_types[1], postfix);
857 		store_plusminus_num(out, op->items[0]);
858 		x_fputc(']', out);
859 		break;
860 	default:
861 		printf("UNKNOWN ADDRESSING MODE %d\n", op->addr_mode);
862 		abort();
863 	}
864 }
865 
866 static void
867 print_operand_gas(FILE *out, struct gas_operand *op, int postfix) {
868 	int	i;
869 
870 	switch (op->addr_mode) {
871 	case 0:
872 		print_item_gas_x86(out, op->items[0], op->item_types[0], postfix);
873 		break;
874 	case ADDR_INDIRECT:
875 		x_fputc('(', out);
876 		print_item_gas_x86(out, op->items[0], op->item_types[0], postfix);
877 		x_fputc(')', out);
878 		break;
879 	case ADDR_SCALED:
880 	case ADDR_SCALED_DISPLACE:
881 		if (op->addr_mode == ADDR_SCALED) {
882 			i = 0;
883 		} else {
884 			i = 1;
885 		}
886 
887 		x_fputc('(', out);
888 		print_item_gas_x86(out, op->items[i], op->item_types[i], postfix);
889 		x_fprintf(out, ",");
890 		++i;
891 		print_item_gas_x86(out, op->items[i], op->item_types[i], postfix);
892 
893 		++i;
894 		if (op->item_types[i] != 0) {
895 			x_fprintf(out, ",");
896 			print_item_gas_x86(out, op->items[i],
897 				op->item_types[i], postfix);
898 		}
899 		if (op->addr_mode == ADDR_SCALED_DISPLACE) {
900 			store_plusminus_num(out, op->items[0]);
901 		}
902 		x_fputc(')', out);
903 		break;
904 	case ADDR_DISPLACE:
905 		store_plusminus_num(out, op->items[0]);
906 		x_fputc('(', out);
907 		print_item_gas_x86(out, op->items[1], op->item_types[1], postfix);
908 		x_fputc(')', out);
909 		break;
910 	default:
911 		printf("UNKNOWN ADDRESSING MODE %d\n", op->addr_mode);
912 		abort();
913 	}
914 }
915 
916 static void
917 do_xlat_nasm(
918 	FILE *out,
919 	/*s truct gas_token *instr_tok,*/ char *name,
920 	struct gas_operand *op,
921 	struct gas_operand *op2,
922 	struct gas_operand *op3,
923 	int postfix) {
924 
925 	x_fprintf(out, "%s", name);
926 	if (op == NULL && postfix == 'l') {
927 		/* stosd, lodsd, etc */
928 		x_fputc('d', out);
929 	}
930 	if (op != NULL) x_fputc(' ', out);
931 	if (op3 != NULL) {
932 		print_operand_nasm(out, op3, postfix);
933 		x_fprintf(out, ", ");
934 	}
935 	if (op2 != NULL) {
936 		print_operand_nasm(out, op2, postfix);
937 		x_fprintf(out, ", ");
938 	}
939 	if (op != NULL) {
940 		print_operand_nasm(out, op, postfix);
941 	}
942 }
943 
944 
945 static void
946 do_xlat_gas(
947 	FILE *out,
948 	/*s truct gas_token *instr_tok,*/ char *name,
949 	struct gas_operand *op,
950 	struct gas_operand *op2,
951 	struct gas_operand *op3,
952 	int postfix) {
953 
954 	x_fprintf(out, "%s", name);
955 	if (postfix) {
956 		x_fputc(postfix, out);
957 	}
958 	if (op != NULL) x_fputc(' ', out);
959 	if (op != NULL) {
960 		print_operand_gas(out, op, postfix);
961 	}
962 	if (op2 != NULL) {
963 		x_fprintf(out, ", ");
964 		print_operand_gas(out, op2, postfix);
965 	}
966 	if (op3 != NULL) {
967 		x_fprintf(out, ", ");
968 		print_operand_gas(out, op3, postfix);
969 	}
970 }
971 
972 /*
973  * Returns instruction operand size (b for byte, w=word, l=longword,
974  * q=qword, t=tword) or zero, in which case no size is specified.
975  *
976  * The operand size is sometimes encoded by the last character and
977  * sometimes not. For example, ``int'' ends with t but doesn't take
978  * a tword argument. If the return value is nonzero, the encoding
979  * last character will be removed from the string.
980  *
981  * XXX This stuff is quite probably incorrect for a vast number of
982  * instructions :-(
983  */
984 static int
985 get_instr_postfix(char *instr, struct gas_operand *op) {
986 	char	*p;
987 	int	postfix = 0;
988 
989 	p = strchr(instr, 0);
990 	--p;
991 	if (instr[0] == 'f') {
992 		/* Floating point */
993 		if (strchr("slt", *p) != NULL) {
994 			/* short (float), long (double) or tword (ldouble) */
995 			postfix = *p;
996 			*p = 0;
997 		}
998 	} else if (op != NULL) { /* XXX correct? */
999 		if (strchr("bwlq", *p) != NULL) {
1000 			/* byte/word/longword(dword)/qword */
1001 			if (strcmp(instr, "leal") == 0) {
1002 				/*
1003 				 * For some reason,
1004 				 * lea eax, dword [eax]
1005 				 * doesn't work in NASM, so let's
1006 				 * omit the size
1007 				 */
1008 				;
1009 			} else {
1010 				postfix = *p;
1011 			}
1012 			*p = 0;
1013 		}
1014 	} else if (op == NULL && *p == 'l') {
1015 		/*
1016 		 * stosd, lodsd, etc are written as stosl, etc
1017 		 */
1018 		postfix = *p;
1019 		*p = 0;
1020 	}
1021 	return postfix;
1022 }
1023 
1024 static void
1025 append_instr(
1026 	struct inline_instr **dest,
1027 	struct inline_instr **dest_tail,
1028 	struct inline_instr *instr) {
1029 
1030 	if (*dest == NULL) {
1031 		*dest = *dest_tail = instr;
1032 	} else {
1033 		(*dest_tail)->next = instr;
1034 		*dest_tail = (*dest_tail)->next;
1035 	}
1036 }
1037 
1038 static struct inline_instr *
1039 do_parse_asm(struct gas_token *tok, struct inline_asm_stmt *stmt) {
1040 	struct gas_token		*t;
1041 	struct gas_token		*nexttok;
1042 	struct inline_instr		*ret = NULL;
1043 	struct inline_instr		*ret_tail = NULL;
1044 	struct inline_instr		*tmp;
1045 	static struct inline_instr	nullinstr;
1046 
1047 	for (t = tok; t != NULL;) {
1048 		if (t->type == GAS_DOTIDENT) {
1049 			/* Assembler directive */
1050 			warningfl(asm_tok,
1051 				"Ignoring assembler directive `%s'",
1052 				t->ascii);
1053 			do {
1054 				t = t->next;
1055 			} while (t && t->type != GAS_SEPARATOR);
1056 		} else if (t->type == GAS_SEPARATOR) {
1057 			;
1058 		} else if ((t->type == GAS_IDENT
1059 			|| GAS_NUMBER(t->type))
1060 			&& t->next
1061 			&& t->next->type == TOK_OP_AMB_COND2) {
1062 			/* Label */
1063 			tmp = n_xmalloc(sizeof *tmp);
1064 			*tmp = nullinstr;
1065 			tmp->type = INLINSTR_LABEL;
1066 			if (t->type == GAS_IDENT) {
1067 				tmp->name = t->data;
1068 			} else {
1069 				tmp->name
1070 					= backend->get_inlineasm_label(t->data);
1071 			}
1072 			t = t->next;
1073 			append_instr(&ret, &ret_tail, tmp);
1074 		} else if (t->type == GAS_IDENT) {
1075 			/* Has to be instruction!? */
1076 			struct gas_operand	*op = NULL;
1077 			struct gas_operand	*op2 = NULL;
1078 			struct gas_token	*t2;
1079 			struct gas_token	*instr_tok = t;
1080 
1081 			t2 = t->next;
1082 			if (t2
1083 				&& t2->type != GAS_SEPARATOR
1084 				&& (op = parse_operand(&t2, stmt)) != NULL) {
1085 				t = t2;
1086 				if (t2 && t2->type == TOK_OP_COMMA) {
1087 					if ((t2 = t2->next) &&
1088 					(op2 = parse_operand(&t2, stmt))
1089 						!= NULL) {
1090 						t = t2;
1091 					}
1092 				}
1093 			}
1094 			if (gas_errors) {
1095 				break;
1096 			}
1097 
1098 			tmp = n_xmalloc(sizeof *tmp);
1099 			*tmp = nullinstr;
1100 			tmp->type = INLINSTR_REAL;
1101 			tmp->name = instr_tok->data;
1102 			tmp->postfix = get_instr_postfix(instr_tok->data, op);
1103 			tmp->operands[0] = op;
1104 			tmp->operands[1] = op2;
1105 			tmp->operands[2] = NULL;
1106 			append_instr(&ret, &ret_tail, tmp);
1107 		} else {
1108 			gas_errorfl(t, "Parse error at `%s' (%d)",
1109 				t->ascii, __LINE__);
1110 		}
1111 		if (t == NULL) {
1112 			break;
1113 		}
1114 		nexttok = t->next;
1115 		/*free_gas_token(t);*/
1116 		t = nexttok;
1117 	}
1118 
1119 	if (gas_errors) {
1120 		free(ret);
1121 		return NULL;
1122 	}
1123 	return ret;
1124 }
1125 
1126 
1127 static void
1128 inline_instr_to_gas_or_nasm(FILE *out, struct inline_instr *code, int to) {
1129 	struct inline_instr	*tmp;
1130 
1131 	for (tmp = code; tmp != NULL; tmp = tmp->next) {
1132 		if (tmp->type == INLINSTR_REAL) {
1133 			if (to == TO_NASM) {
1134 				do_xlat_nasm(out, tmp->name, tmp->operands[0],
1135 					tmp->operands[1], NULL, tmp->postfix);
1136 			} else {
1137 				do_xlat_gas(out, tmp->name, tmp->operands[0],
1138 					tmp->operands[1], NULL, tmp->postfix);
1139 			}
1140 		} else if (tmp->type == INLINSTR_LABEL) {
1141 			emit->label(tmp->name, 0);
1142 		} else if (tmp->type == INLINSTR_ASM) {
1143 		}
1144 		x_fputc('\n', out);
1145 	}
1146 }
1147 
1148 void
1149 inline_instr_to_nasm(FILE *out, struct inline_instr *code) {
1150 	inline_instr_to_gas_or_nasm(out, code, TO_NASM);
1151 }
1152 
1153 void
1154 inline_instr_to_gas(FILE *out, struct inline_instr *code) {
1155 	inline_instr_to_gas_or_nasm(out, code, TO_GAS);
1156 }
1157 
1158 static struct inline_asm_io *
1159 get_iolist(struct token **tok, int is_output, int *err, int *n_items,
1160 	struct inline_asm_stmt *data) {
1161 
1162 	struct token		*t;
1163 	struct inline_asm_io	*ret = NULL;
1164 	struct inline_asm_io	*ret_tail = NULL;
1165 	struct expr		*ex;
1166 
1167 	*n_items = 0;
1168 	*err = 1;
1169 	if (next_token(tok) != 0) {
1170 		return NULL;
1171 	}
1172 	for (t = *tok; t != NULL; t = t->next) {
1173 		if (t->type == TOK_OPERATOR
1174 			&& *(int *)t->data == TOK_OP_AMB_COND2) {
1175 			/* Terminating : */
1176 			break;
1177 		} else if (t->type == TOK_PAREN_CLOSE) {
1178 			/* Entire asm statement ends here */
1179 			break;
1180 		} else if (t->type == TOK_STRING_LITERAL) {
1181 			struct inline_asm_io	*tmp;
1182 			char			*constraints = t->ascii;
1183 
1184 			if (is_output) {
1185 				char	*p;
1186 
1187 				if ((p = strchr(constraints, '=')) == NULL) {
1188 					if (strchr(constraints, '+') == NULL) {
1189 						errorfl(t, "Output operand "
1190 						"constraints lack `='");
1191 						return NULL;
1192 					}
1193 				} else if (constraints[0] != '=') {
1194 					warningfl(t, "Output operand "
1195 						"constraints don't begin "
1196 						"with `='");
1197 					memmove(p, p + 1, strlen(p));
1198 				}
1199 			}
1200 
1201 			/*
1202 			 * "constraints" (expr)
1203 			 */
1204 			if (expect_token(&t, TOK_PAREN_OPEN, 1) != 0) {
1205 				return NULL;
1206 			}
1207 			ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, 0, 1);
1208 			if (ex == NULL) {
1209 				return NULL;
1210 			}
1211 			tmp = n_xmalloc(sizeof *tmp);
1212 			if (is_output && constraints[0] == '=') {
1213 				tmp->constraints = constraints + 1;
1214 			} else {
1215 				tmp->constraints = constraints;
1216 			}
1217 			if (isdigit((unsigned char)*tmp->constraints)) {
1218 				tmp->constraints = get_constraint_by_idx(
1219 					data, *tmp->constraints - '0');
1220 				if (tmp->constraints == NULL) {
1221 					return NULL;
1222 				}
1223 			}
1224 			tmp->expr = ex; /* XXX list order ok? */
1225 			tmp->next = NULL;
1226 			tmp->index = *n_items;
1227 			if (ret == NULL) {
1228 				ret = ret_tail = tmp;
1229 			} else {
1230 				ret_tail->next = tmp;
1231 				ret_tail = tmp;
1232 			}
1233 			++*n_items;
1234 			if (next_token(&t) != 0) {
1235 				return NULL;
1236 			}
1237 			if (t->type == TOK_OPERATOR
1238 				&& *(int *)t->data == TOK_OP_COMMA) {
1239 				;
1240 			} else if (t->type == TOK_PAREN_CLOSE) {
1241 				break;
1242 			} else if (t->type == TOK_OPERATOR
1243 				&& *(int *)t->data == TOK_OP_AMB_COND2) {
1244 				break;
1245 			} else {
1246 				errorfl(t, "Parse error at `%s'", t->ascii);
1247 				return NULL;
1248 			}
1249 		} else {
1250 			errorfl(t, "Parse error at `%s'", t->ascii);
1251 			return NULL;
1252 		}
1253 	}
1254 	*err = 0;
1255 	*tok = t;
1256 
1257 	return ret;
1258 }
1259 
1260 static void
1261 free_iolist(struct inline_asm_io *io) {
1262 	struct inline_asm_io	*tmp;
1263 
1264 	while (io != NULL) {
1265 		tmp = io->next;
1266 		free(io);
1267 		io = tmp;
1268 	}
1269 }
1270 
1271 static void
1272 resolve_constraint_refs(struct inline_asm_stmt *stmt,
1273 		struct inline_asm_io *iotmp,
1274 		int is_output) {
1275 
1276 	struct inline_asm_io	*mapped;
1277 
1278 	if (iotmp->constraints[0] != '%'
1279 		|| !isdigit((unsigned char)iotmp->constraints[1])) {
1280 		/* Nothing to do */
1281 		return;
1282 	}
1283 	mapped = get_operand_by_idx(stmt, NULL,
1284 		strtol(iotmp->constraints+1, NULL, 10),
1285 		NULL);
1286 	if (mapped == NULL) {
1287 		errorfl(NULL, "Referenced constraint `%s' doesn't exist",
1288 			iotmp->constraints);
1289 		return;
1290 	}
1291 	iotmp->constraints = n_xmalloc(strlen(mapped->constraints + 2));
1292 	if (is_output) {
1293 		*iotmp->constraints = '=';
1294 		strcpy(iotmp->constraints+1, mapped->constraints);
1295 	} else {
1296 		char	*p;
1297 		char	*dest = iotmp->constraints;
1298 
1299 		for (p = mapped->constraints; *p != 0; ++p) {
1300 			if (*p != '=') {
1301 				*dest++ = *p;
1302 			}
1303 		}
1304 		*dest = 0;
1305 	}
1306 }
1307 
1308 struct inline_asm_stmt *
1309 parse_inline_asm(struct token **tok) {
1310 	struct token			*t;
1311 	struct inline_asm_stmt		*ret;
1312 	static struct inline_asm_stmt	nullstmt;
1313 	struct gas_token		*gt = NULL;
1314 	static int			warned = 0;
1315 	int				err;
1316 	struct inline_asm_io		*iotmp;
1317 
1318 #if !defined(__FreeBSD__) && !defined(__DragonFly__) /* FreeBSD uses inline asm heavily in the headers ... */
1319 	if (!warned) {
1320 		warningfl(*tok, "nwcc inline assembly support is new, "
1321 			"incomplete and unproven");
1322 		warned = 1;
1323 	}
1324 #endif
1325 
1326 	gas_errors = 0;
1327 
1328 	if ((*tok)->next && (*tok)->next->type == TOK_KEY_VOLATILE) {
1329 		/*
1330 		 * __asm__ __volatile__("...");
1331 		 */
1332 		if (next_token(tok) != 0) {
1333 			return NULL;
1334 		}
1335 	}
1336 	if (expect_token(tok, TOK_PAREN_OPEN, 1) != 0) {
1337 		return NULL;
1338 	}
1339 
1340 	asm_tok = t = *tok;
1341 	if (t->type != TOK_STRING_LITERAL) {
1342 		errorfl(t, "Parse error at `%s' (%d)",
1343 			t->ascii, __LINE__);
1344 		return NULL;
1345 	}
1346 	/*
1347 	 * Syntax:
1348 	 * "code" : output : input : clobbered
1349 	 *        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ optional
1350 	 */
1351 
1352 	ret = n_xmalloc(sizeof *ret);
1353 	*ret = nullstmt;
1354 	if (*t->ascii != 0) {
1355 		if ((gt = tokenize_gas_code(t->ascii)) == NULL) {
1356 			recover(&t, TOK_PAREN_CLOSE, 0);
1357 			return NULL;
1358 		}
1359 	}
1360 
1361 	if (next_token(&t) != 0) {
1362 		return NULL;
1363 	}
1364 	err = 0;
1365 	if (t->type == TOK_OPERATOR
1366 		&& *(int *)t->data == TOK_OP_AMB_COND2) {
1367 		int	n;
1368 
1369 		ret->extended = 1;
1370 		/* Output specified? */
1371 		if ((ret->output = get_iolist(&t, 1, &err, &n, ret)) == NULL
1372 			&& err) {
1373 		} else if (t->type == TOK_OPERATOR
1374 			&& *(int *)t->data == TOK_OP_AMB_COND2) {
1375 			ret->n_outputs = n;
1376 			/* Input specified? */
1377 			if ((ret->input = get_iolist(&t, 0, &err, &n, ret)) == NULL
1378 				&& err) {
1379 				free_iolist(ret->output);
1380 			} else {
1381 				ret->n_inputs = n;
1382 			}
1383 		} else {
1384 			ret->n_outputs = n;
1385 		}
1386 		if (err == 0
1387 			&& t->type == TOK_OPERATOR
1388 			&& *(int *)t->data == TOK_OP_AMB_COND2) {
1389 			/* Clobbered register list */
1390 			for (t = t->next; t != NULL; t = t->next) {
1391 				if (t->type == TOK_STRING_LITERAL) {
1392 					struct clobbered_reg	*cr;
1393 
1394 					cr = n_xmalloc(sizeof *cr);
1395 					cr->reg = backend->
1396 						name_to_reg(t->ascii);
1397 					if (cr->reg == NULL
1398 						&& strcmp(t->ascii, "memory")
1399 						!= 0
1400 						&& strcmp(t->ascii, "cc") != 0) {
1401 						errorfl(t,
1402 							"Unknown register `%s'",
1403 							t->ascii);
1404 						return NULL;
1405 					}
1406 					cr->next = ret->clobbered;
1407 					ret->clobbered = cr;
1408 					if ((t = t->next) == NULL) {
1409 						break;
1410 					} else if (t->type == TOK_OPERATOR
1411 						&& *(int *)t->data
1412 						== TOK_OP_COMMA) {
1413 						; /* ok */
1414 					} else if (t->type
1415 						== TOK_PAREN_CLOSE) {
1416 						break;
1417 					}
1418 				} else {
1419 					errorfl(t, "Parse error at `%s'",
1420 						t->ascii);
1421 					return NULL;
1422 				}
1423 			}
1424 			if (t == NULL) {
1425 				errorfl(NULL, "Premature end of file");
1426 				return NULL;
1427 			}
1428 		}
1429 	} else if (t->type == TOK_PAREN_CLOSE) {
1430 		; /* done */
1431 
1432 	}
1433 
1434 	if (t->type != TOK_PAREN_CLOSE) {
1435 		errorfl(t, "Parse error at `%s' (%d)",
1436 			t->ascii, __LINE__);
1437 		recover(&t, TOK_PAREN_CLOSE, 0);
1438 		return NULL;
1439 	}
1440 	*tok = t;
1441 
1442 	if (!err && gt != NULL) {
1443 		ret->code = do_parse_asm(gt, ret);
1444 	}
1445 	/*free_gas_token_list(gt);*/
1446 	if (err) {
1447 		free(ret);
1448 		return NULL;
1449 	}
1450 	ret->toklist = gt;
1451 
1452 	/*
1453 	 * 07/11/09: Resolve references to other I/O constraints. E.g.
1454 	 *
1455 	 *    __asm__("..." : "=r" (x) : "%0" (y));
1456 	 *
1457 	 * ... will copy the %0 constraint "=r" for for the %1
1458 	 * constraint (except it removes = because %1 is an input
1459 	 * operand)
1460 	 */
1461 	for (iotmp = ret->input; iotmp != NULL; iotmp = iotmp->next) {
1462 		resolve_constraint_refs(ret, iotmp, 0);
1463 	}
1464 	for (iotmp = ret->output; iotmp != NULL; iotmp = iotmp->next) {
1465 		resolve_constraint_refs(ret, iotmp, 1);
1466 	}
1467 
1468 	return ret;
1469 }
1470 
1471 
1472 char *
1473 parse_asm_varname(struct token **curtok) {
1474 	char	*asmname;
1475 
1476 	if (expect_token(curtok, TOK_PAREN_OPEN, 1) != 0) {
1477 		return NULL;
1478 	}
1479 	if ((*curtok)->type != TOK_STRING_LITERAL) {
1480 		errorfl(*curtok, "Parse error at `%s'", (*curtok)->ascii);
1481 		return NULL;
1482 	}
1483 	asmname = (*curtok)->ascii;
1484 	if (expect_token(curtok, TOK_PAREN_CLOSE, 1) != 0) {
1485 		return NULL;
1486 	}
1487 	return asmname;
1488 }
1489 
1490