1/*	$NetBSD: gspa.c,v 1.14 2009/04/15 08:26:35 lukem Exp $	*/
2/*
3 * GSP assembler main program
4 *
5 * Copyright (c) 1993 Paul Mackerras.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *      This product includes software developed by Paul Mackerras.
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35#ifndef lint
36__RCSID("$NetBSD: gspa.c,v 1.14 2009/04/15 08:26:35 lukem Exp $");
37#endif
38
39#include <sys/param.h>
40#include <err.h>
41#include <errno.h>
42#include <setjmp.h>
43#include <stdarg.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48#include <util.h>
49
50#include "gsp_ass.h"
51#include "gsp_gram.h"
52
53#define YYDEBUG_VALUE	0
54
55extern YYSTYPE yylval;
56int err_count;
57
58char line[MAXLINE];
59unsigned lineno;
60
61extern int yydebug;
62short pass2;
63
64unsigned pc;
65unsigned highest_pc;
66unsigned line_pc;
67
68FILE *infile;
69FILE *current_infile;
70FILE *objfile;
71FILE *listfile;
72
73char *c_name;
74char in_name[PATH_MAX + 1];
75
76struct input {
77	FILE	*fp;
78	struct input *next;
79	int	lineno;
80	char	name[128];
81} *pending_input;
82
83jmp_buf synerrjmp;
84
85void	setext(char *, const char *, const char *);
86__dead static void	usage(void);
87int	yyparse(void);
88
89void	c_dumpbuf(void);
90
91int
92main(int argc, char **argv)
93{
94	char * volatile hex_name;
95	char * volatile list_name;
96	int c;
97
98	hex_name = list_name = 0;
99
100	/* parse options */
101	while ((c = getopt(argc, argv, "o:l:c:")) != -1) {
102		switch (c) {
103		case 'o':
104			if (hex_name)
105				usage();
106			hex_name = optarg;
107			break;
108		case 'c':
109			if (c_name)
110				usage();
111			c_name = optarg;
112			break;
113		case 'l':
114			if (list_name)
115				usage();
116			list_name = optarg;
117			break;
118		default:
119			usage();
120		}
121	}
122
123	/* get source file */
124	argc -= optind;
125	argv += optind;
126	if (argc == 0) {
127		infile = stdin;
128		strlcpy(in_name, "<stdin>", sizeof(in_name));
129	} else if (argc == 1) {
130		strlcpy(in_name, *argv, sizeof(in_name));
131		if ((infile = fopen(in_name, "r")) == NULL)
132			err(1, "fopen");
133	} else
134		usage();
135
136	/* Pass 1 */
137	pending_input = NULL;
138	current_infile = infile;
139
140	yydebug = YYDEBUG_VALUE;
141	pass2 = 0;
142	pc = 0;
143	lineno = 0;
144	while( get_line(line, MAXLINE) ){
145		if( !setjmp(synerrjmp) ){
146			lex_init(line);
147			yyparse();
148		}
149	}
150	if( err_count > 0 )
151		exit(1);
152
153	/* Open output files */
154	if (hex_name == 0)
155		objfile = stdout;
156	else if ((objfile = fopen(hex_name, "w")) == NULL)
157		err(1, "fopen");
158	if (c_name) {
159		fprintf(objfile, "/*\n"
160		    " * This file was automatically created from\n"
161		    " * a TMS34010 assembler output file.\n"
162		    " * Do not edit manually.\n"
163		    " */\n"
164		    "#include <sys/types.h>\n"
165		    "u_int16_t %s[] = {\n\t", c_name);
166	}
167	if (list_name)
168		if ((listfile = fopen(list_name, "w")) == NULL)
169			err(1, "fopen");
170
171	/* Pass 2 */
172	pass2 = 1;
173	rewind(infile);
174	current_infile = infile;
175	pc = 0;
176	lineno = 0;
177	reset_numeric_labels();
178	while( get_line(line, MAXLINE) ){
179		line_pc = pc;
180		if( !setjmp(synerrjmp) ){
181			lex_init(line);
182			yyparse();
183		}
184		listing();
185	}
186
187	if (c_name) {
188		c_dumpbuf();
189		fprintf(objfile, "\n\t0\n};\n");
190	}
191
192	exit(err_count != 0);
193}
194
195void
196setext(char *out, const char *in, const char *ext)
197{
198	const char *p;
199
200	p = strrchr(in, '.');
201	if( p != NULL ){
202		memcpy(out, in, p - in);
203		strcpy(out + (p - in), ext);
204	} else {
205		strcpy(out, in);
206		strcat(out, ext);
207	}
208}
209
210void
211push_input(char *fn)
212{
213	FILE *f;
214	struct input *p;
215
216	f = fopen(fn, "r");
217	if( f == NULL ){
218		p1err("Can't open input file %s", fn);
219		return;
220	}
221	new(p);
222	p->fp = current_infile;
223	p->lineno = lineno;
224	strlcpy(p->name, in_name, sizeof(p->name));
225	p->next = pending_input;
226	current_infile = f;
227	lineno = 1;
228	strlcpy(in_name, fn, sizeof(in_name));
229	pending_input = p;
230}
231
232int
233get_line(char *lp, int maxlen)
234{
235	struct input *p;
236
237	while( fgets(lp, maxlen, current_infile) == NULL ){
238		if( (p = pending_input) == NULL )
239			return 0;
240		/* pop the input stack */
241		fclose(current_infile);
242		current_infile = p->fp;
243		strlcpy(in_name, p->name, sizeof(in_name));
244		lineno = p->lineno;
245		pending_input = p->next;
246		free(p);
247	}
248	++lineno;
249	return 1;
250}
251
252void
253perr(const char *fmt, ...)
254{
255	va_list ap;
256	char error_string[256];
257
258	if( !pass2 )
259		return;
260	fprintf(stderr, "Error in line %d: ", lineno);
261	va_start(ap, fmt);
262	vsprintf(error_string, fmt, ap);
263	va_end(ap);
264	fprintf(stderr, "%s\n", error_string);
265	list_error(error_string);
266	++err_count;
267}
268
269void
270p1err(const char *fmt, ...)
271{
272	va_list ap;
273
274	fprintf(stderr, "Pass 1 error in line %d: ", lineno);
275	va_start(ap, fmt);
276	vfprintf(stderr, fmt, ap);
277	va_end(ap);
278	fprintf(stderr, "\n");
279	++err_count;
280}
281
282void
283yyerror(const char *errs)
284{
285
286	perr("%s", errs);
287	longjmp(synerrjmp, 1);
288}
289
290static void
291usage(void)
292{
293	fprintf(stderr,
294		"Usage: gspa [-c c_array_name] [-l list_file] [-o hex_file] [infile]\n");
295	exit(1);
296}
297