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