#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gspa.c,v 1.16 2025/11/24 08:04:28 nia Exp $");
#endif
#include <sys/param.h>
#include <err.h>
#include <errno.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#include "gsp_ass.h"
#include "gsp_gram.h"
#define YYDEBUG_VALUE 0
extern YYSTYPE yylval;
int err_count;
char line[MAXLINE];
unsigned lineno;
extern int yydebug;
short pass2;
unsigned pc;
unsigned highest_pc;
unsigned line_pc;
FILE *infile;
FILE *current_infile;
FILE *objfile;
FILE *listfile;
char *c_name;
char in_name[PATH_MAX + 1];
struct input {
FILE *fp;
struct input *next;
int lineno;
char name[128];
} *pending_input;
jmp_buf synerrjmp;
void setext(char *, const char *, const char *);
__dead static void usage(void);
int yyparse(void);
void c_dumpbuf(void);
int
main(int argc, char **argv)
{
char * volatile hex_name;
char * volatile list_name;
int c;
hex_name = list_name = 0;
while ((c = getopt(argc, argv, "o:l:c:")) != -1) {
switch (c) {
case 'o':
if (hex_name)
usage();
hex_name = optarg;
break;
case 'c':
if (c_name)
usage();
c_name = optarg;
break;
case 'l':
if (list_name)
usage();
list_name = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc == 0) {
infile = stdin;
strlcpy(in_name, "<stdin>", sizeof(in_name));
} else if (argc == 1) {
strlcpy(in_name, *argv, sizeof(in_name));
if ((infile = fopen(in_name, "r")) == NULL)
err(1, "fopen");
} else
usage();
pending_input = NULL;
current_infile = infile;
yydebug = YYDEBUG_VALUE;
pass2 = 0;
pc = 0;
lineno = 0;
while( get_line(line, MAXLINE) ){
if( !setjmp(synerrjmp) ){
lex_init(line);
yyparse();
}
}
if( err_count > 0 )
exit(1);
if (hex_name == 0)
objfile = stdout;
else if ((objfile = fopen(hex_name, "w")) == NULL)
err(1, "fopen");
if (c_name) {
fprintf(objfile, "/*\n"
" * This file was automatically created from\n"
" * a TMS34010 assembler output file.\n"
" * Do not edit manually.\n"
" */\n"
"#include <sys/types.h>\n"
"u_int16_t %s[] = {\n\t", c_name);
}
if (list_name)
if ((listfile = fopen(list_name, "w")) == NULL)
err(1, "fopen");
pass2 = 1;
rewind(infile);
current_infile = infile;
pc = 0;
lineno = 0;
reset_numeric_labels();
while( get_line(line, MAXLINE) ){
line_pc = pc;
if( !setjmp(synerrjmp) ){
lex_init(line);
yyparse();
}
listing();
}
if (c_name) {
c_dumpbuf();
fprintf(objfile, "\n\t0\n};\n");
}
exit(err_count != 0);
}
void
setext(char *out, const char *in, const char *ext)
{
const char *p;
p = strrchr(in, '.');
if( p != NULL ){
memcpy(out, in, p - in);
strcpy(out + (p - in), ext);
} else {
strcpy(out, in);
strcat(out, ext);
}
}
void
push_input(char *fn)
{
FILE *f;
struct input *p;
f = fopen(fn, "r");
if( f == NULL ){
p1err("Can't open input file %s", fn);
return;
}
new(p);
p->fp = current_infile;
p->lineno = lineno;
strlcpy(p->name, in_name, sizeof(p->name));
p->next = pending_input;
current_infile = f;
lineno = 1;
strlcpy(in_name, fn, sizeof(in_name));
pending_input = p;
}
int
get_line(char *lp, int maxlen)
{
struct input *p;
while( fgets(lp, maxlen, current_infile) == NULL ){
if( (p = pending_input) == NULL )
return 0;
fclose(current_infile);
current_infile = p->fp;
strlcpy(in_name, p->name, sizeof(in_name));
lineno = p->lineno;
pending_input = p->next;
free(p);
}
++lineno;
return 1;
}
void
perr(const char *fmt, ...)
{
va_list ap;
char error_string[256];
if( !pass2 )
return;
fprintf(stderr, "Error in line %d: ", lineno);
va_start(ap, fmt);
vsprintf(error_string, fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", error_string);
list_error(error_string);
++err_count;
}
void
p1err(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "Pass 1 error in line %d: ", lineno);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
++err_count;
}
void
yyerror(const char *errs)
{
perr("%s", errs);
longjmp(synerrjmp, 1);
}
static void
usage(void)
{
fprintf(stderr,
"Usage: gspa [-c c_array_name] [-l list_file] [-o hex_file] [infile]\n");
exit(1);
}