Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | mjames | 1 | /* |
2 | * hdl.y parser for verilog net lists |
||
3 | * by Frank Bennett |
||
4 | * |
||
5 | * i.e. hdl s.g |
||
6 | * products two files: s.nam, s.seq - 1 net per line |
||
7 | * s.seq is sorted by reference designator |
||
8 | * s.nam is sorted by netname |
||
9 | * |
||
10 | * - primarily handles "flat" verilog HDL netlists. |
||
11 | * - parses hierarchical netlist but currently doesn't flatten them. |
||
12 | * - concatenated signal names need to be expanded. currently the whole |
||
13 | * netname bundle is given the name : "concatenation" |
||
14 | * - not included : |
||
15 | * Behavioral Statements |
||
16 | * Specify blocks |
||
17 | * |
||
18 | * PD yacc : |
||
19 | * byacc, Bob Corbett. Berkely yacc adapted for MINIX by Peter Housel |
||
20 | * COLOGNE:commands/lex-yacc/byacc.tar.Z |
||
21 | * |
||
22 | * DOS extender - 386 to avoid malloc problems |
||
23 | * djgpp.zip |
||
24 | * wuarchive.wustl.edu (128.252.135.4): /mirrors3/garbo.uwasa.fi/programming |
||
25 | */ |
||
26 | %{ |
||
27 | #define YYDEBUG 1 |
||
28 | #include <string.h> |
||
29 | #include <ctype.h> |
||
30 | #include <errno.h> |
||
31 | #include <stdio.h> |
||
32 | #include <fcntl.h> |
||
33 | |||
34 | #define out(c) putc(c,yyout) |
||
35 | #define NCOM 300 |
||
36 | |||
37 | int bug=0, ind ; |
||
38 | FILE *fopen(), *freopen(), *fi, *ft, *fo, *fr ; |
||
39 | static int i, comment=0; |
||
40 | char *cp, *st, refd[20], part[20] ; |
||
41 | char ln[80] ; |
||
42 | |||
43 | extern char *strsave(), *malloc(); |
||
44 | extern int yyleng, lexval ; |
||
45 | extern char yytext[]; |
||
46 | extern char yysbuf[]; |
||
47 | |||
48 | typedef struct YYS_TYPE { /* use instead of %union below */ |
||
49 | int i; |
||
50 | char s[50]; |
||
51 | } yys_type ; |
||
52 | #define YYSTYPE yys_type |
||
53 | |||
54 | |||
55 | # define YYLMAX 132 |
||
56 | |||
57 | int yylineno =0; |
||
58 | int yyleng ; |
||
59 | char yytext[YYLMAX]; |
||
60 | char yysbuf[YYLMAX]; |
||
61 | char modnam[YYLMAX]; |
||
62 | int yysptr = -1, yylast, toklast; |
||
63 | FILE *yyout; |
||
64 | #define YYNL 10 |
||
65 | |||
66 | |||
67 | %} |
||
68 | |||
69 | /* HP-UX yacc seems to be fussy about : |
||
70 | %union { |
||
71 | int i; |
||
72 | char s[50]; |
||
73 | } |
||
74 | */ |
||
75 | |||
76 | %token NL NAME NUMBER MODULE ENDMODULE WIRE INPUT OUTPUT INOUT |
||
77 | %token NETTYPE ASSIGN STRENGTH0 STRENGTH1 GATETYPE INITIAL |
||
78 | %token PARAMETER REG TIME INTEGER REAL EVENT DEFPARAM |
||
79 | %token BIN_OP UNARY_OP PRIMITIVE ENDPRIM TABLE ENDTABLE |
||
80 | %token OUT_SYM LEV_SYM EDGE_SYM |
||
81 | |||
82 | %left BIN_OP |
||
83 | |||
84 | %start modules |
||
85 | |||
86 | %% |
||
87 | modules : modules mod_prim |
||
88 | | modules error |
||
89 | | mod_prim |
||
90 | ; |
||
91 | |||
92 | mod_prim : module |
||
93 | | primitive |
||
94 | ; |
||
95 | |||
96 | primitive : PRIMITIVE NAME '(' list_of_vars ')' ';' prim_body ENDPRIM |
||
97 | ; |
||
98 | |||
99 | list_of_vars : list_of_vars ',' NAME |
||
100 | | NAME |
||
101 | ; |
||
102 | |||
103 | prim_body : UDP_decl UDP_init table_def |
||
104 | | UDP_decl table_def |
||
105 | ; |
||
106 | |||
107 | UDP_decl : output_decl |
||
108 | | input_decl |
||
109 | | reg_decl |
||
110 | ; |
||
111 | |||
112 | UDP_init : INITIAL NAME '=' init_val |
||
113 | ; |
||
114 | |||
115 | init_val : '1' '\'' 'b' '0' |
||
116 | | '1' '\'' 'b' '1' |
||
117 | | '1' '\'' 'b' 'x' |
||
118 | | '1' |
||
119 | | '0' |
||
120 | ; |
||
121 | |||
122 | table_def : TABLE table_entries ENDTABLE |
||
123 | ; |
||
124 | |||
125 | table_entries : table_entries combin_entry |
||
126 | | combin_entry |
||
127 | | table_entries seq_entry |
||
128 | | seq_entry |
||
129 | ; |
||
130 | |||
131 | combin_entry : level_in_list ':' OUT_SYM ';' |
||
132 | ; |
||
133 | |||
134 | seq_entry : level_in_list ':' state ':' next_state ';' |
||
135 | | edge_in_list ':' state ':' next_state ';' |
||
136 | ; |
||
137 | |||
138 | level_in_list : LEV_SYM |
||
139 | ; |
||
140 | |||
141 | edge_in_list : LEV_SYM edge LEV_SYM |
||
142 | | edge |
||
143 | ; |
||
144 | |||
145 | edge : '(' LEV_SYM LEV_SYM ')' |
||
146 | | EDGE_SYM |
||
147 | ; |
||
148 | |||
149 | state : LEV_SYM |
||
150 | ; |
||
151 | next_state : OUT_SYM |
||
152 | ; |
||
153 | |||
154 | module : MODULE NAME ';' mod_body ENDMODULE |
||
155 | | MODULE NAME '('list_of_ports')' ';' mod_body ENDMODULE |
||
156 | ; |
||
157 | |||
158 | list_of_ports : list_of_ports ',' port |
||
159 | | port |
||
160 | ; |
||
161 | |||
162 | port : NAME |
||
163 | | NAME '[' const_exp ']' |
||
164 | | NAME '[' const_exp ':' const_exp ']' |
||
165 | ; |
||
166 | |||
167 | mod_body : mod_body module_item |
||
168 | | module_item |
||
169 | ; |
||
170 | |||
171 | module_item : param_decl |
||
172 | | input_decl |
||
173 | | output_decl |
||
174 | | inout_decl |
||
175 | | net_decl |
||
176 | | reg_decl |
||
177 | | time_decl |
||
178 | | integer_decl |
||
179 | | real_decl |
||
180 | | event_decl |
||
181 | | gate_decl |
||
182 | | module_instant |
||
183 | | defparm_decl |
||
184 | | cont_assign |
||
185 | ; |
||
186 | |||
187 | param_decl : PARAMETER |
||
188 | ; |
||
189 | reg_decl : REG |
||
190 | ; |
||
191 | time_decl : TIME |
||
192 | ; |
||
193 | integer_decl : INTEGER |
||
194 | ; |
||
195 | real_decl : REAL |
||
196 | ; |
||
197 | event_decl : EVENT |
||
198 | ; |
||
199 | defparm_decl : DEFPARAM |
||
200 | ; |
||
201 | gate_decl : GATETYPE gate_instant |
||
202 | | GATETYPE dr_strength gate_instant |
||
203 | | GATETYPE delay gate_instant |
||
204 | | GATETYPE dr_strength delay gate_instant |
||
205 | ; |
||
206 | |||
207 | gate_instant : NAME '(' exp ')' |
||
208 | ; |
||
209 | |||
210 | input_decl : INPUT list_vars ';' |
||
211 | | INPUT range list_vars ';' |
||
212 | ; |
||
213 | |||
214 | output_decl : OUTPUT list_vars ';' |
||
215 | | OUTPUT range list_vars ';' |
||
216 | ; |
||
217 | |||
218 | inout_decl : INOUT list_vars ';' |
||
219 | | INOUT range list_vars ';' |
||
220 | ; |
||
221 | |||
222 | net_decl : NETTYPE list_vars ';' |
||
223 | | NETTYPE range list_vars ';' |
||
224 | | NETTYPE delay list_vars ';' |
||
225 | | NETTYPE range delay list_vars ';' |
||
226 | ; |
||
227 | |||
228 | range : '[' const_exp ':' const_exp ']' |
||
229 | ; |
||
230 | |||
231 | delay : '#' number |
||
232 | | '#' NAME |
||
233 | ; |
||
234 | |||
235 | dr_strength : '(' STRENGTH0 ',' STRENGTH1 ')' |
||
236 | | '(' STRENGTH1 ',' STRENGTH0 ')' |
||
237 | ; |
||
238 | |||
239 | list_vars : list_vars ',' NAME |
||
240 | | NAME |
||
241 | ; |
||
242 | |||
243 | module_instant : name_mod mod_inst_list ';' |
||
244 | | name_mod par_val mod_inst_list ';' |
||
245 | ; |
||
246 | |||
247 | name_mod : NAME |
||
248 | { strcpy( part, yytext); } |
||
249 | ; |
||
250 | |||
251 | mod_inst_list : mod_inst_list ',' mod_inst |
||
252 | | mod_inst |
||
253 | ; |
||
254 | |||
255 | mod_inst : reference '(' list_mod_conn ')' |
||
256 | | reference '(' list_nam_conn ')' |
||
257 | ; |
||
258 | |||
259 | reference : NAME |
||
260 | { strcpy( refd, yytext); } |
||
261 | ; |
||
262 | |||
263 | list_mod_conn : list_mod_conn ',' exp |
||
264 | | exp |
||
265 | ; |
||
266 | |||
267 | list_nam_conn : list_nam_conn ',' nam_conn |
||
268 | | nam_conn |
||
269 | ; |
||
270 | |||
271 | nam_conn : '.' NAME '(' sig_nam ')' |
||
272 | { |
||
273 | fprintf(fo,"%-18s %-22s %-10s %10s %s\n", |
||
274 | $4.s, refd, $2.s, part, modnam); |
||
275 | } |
||
276 | ; |
||
277 | |||
278 | sig_nam : NAME |
||
279 | | NAME '[' exp ']' |
||
280 | { strcpy($$.s, $1.s); |
||
281 | strcat($$.s, "["); |
||
282 | strcat($$.s, $3.s); |
||
283 | strcat($$.s, "]"); |
||
284 | } |
||
285 | | NAME '[' exp ':' exp ']' |
||
286 | { strcpy($$.s, $1.s); |
||
287 | strcat($$.s, "["); |
||
288 | strcat($$.s, $3.s); |
||
289 | strcat($$.s, ":"); |
||
290 | strcat($$.s, $5.s); |
||
291 | strcat($$.s, "]"); |
||
292 | } |
||
293 | | concatenation |
||
294 | { strcpy($$.s, "concatenation");} |
||
295 | ; |
||
296 | |||
297 | par_val : '#' '(' exp ')' |
||
298 | ; |
||
299 | |||
300 | cont_assign : ASSIGN list_assigns ';' |
||
301 | | ASSIGN dr_strength list_assigns ';' |
||
302 | | ASSIGN delay list_assigns ';' |
||
303 | | ASSIGN dr_strength delay list_assigns ';' |
||
304 | ; |
||
305 | |||
306 | list_assigns : list_assigns ',' assignment |
||
307 | | assignment |
||
308 | ; |
||
309 | |||
310 | assignment : lvalue '=' exp |
||
311 | | lvalue '=' '(' exp ')' |
||
312 | ; |
||
313 | |||
314 | lvalue : NAME |
||
315 | | NAME '[' exp ']' |
||
316 | | concatenation |
||
317 | ; |
||
318 | |||
319 | const_exp : exp |
||
320 | ; |
||
321 | |||
322 | concatenation : '{' exp_list '}' |
||
323 | ; |
||
324 | |||
325 | exp_list : exp_list ',' exp |
||
326 | | exp |
||
327 | ; |
||
328 | |||
329 | exp : primary |
||
330 | | UNARY_OP primary |
||
331 | | UNARY_OP '(' exp ')' |
||
332 | | exp BIN_OP exp |
||
333 | ; |
||
334 | |||
335 | primary : number |
||
336 | | NAME '[' exp ']' |
||
337 | | NAME |
||
338 | | concatenation |
||
339 | ; |
||
340 | |||
341 | number : NUMBER |
||
342 | | NUMBER '\'' 'b' NUMBER |
||
343 | | NUMBER '\'' 'd' NUMBER |
||
344 | | NUMBER '\'' 'o' NUMBER |
||
345 | ; |
||
346 | |||
347 | %% /* start of main */ |
||
348 | |||
349 | main(argc,argv) |
||
350 | int argc; |
||
351 | char *argv[]; |
||
352 | { |
||
353 | int i,p; |
||
354 | char frnam[60], fsnam[60]; |
||
355 | yyout =stderr; |
||
356 | |||
357 | |||
358 | if(argc == 1) { |
||
359 | fprintf(stderr,"use:hdl [-ds] file\n"); exit(1); |
||
360 | } |
||
361 | for(i=1; i<argc; i++) |
||
362 | if(argv[i][0] == '-'){ |
||
363 | bug = ((argv[i][1] == 'd') || (argv[i][2] == 'd')); |
||
364 | } |
||
365 | else break; |
||
366 | |||
367 | |||
368 | if(freopen( argv[i],"r",stdin) == NULL){ |
||
369 | fprintf(stderr,"can't open %s\n", argv[i]);exit(1); |
||
370 | } else { |
||
371 | /* open output */ |
||
372 | for( cp=argv[i], st=fsnam ; *cp && *cp != '.' ; )*st++ = *cp++; |
||
373 | *st = 0; |
||
374 | strcpy( frnam, fsnam ); |
||
375 | strcat( frnam, ".nam"); strcat( fsnam, ".seq"); |
||
376 | |||
377 | if((fo = fopen(fsnam, "w")) == NULL) err("can't open %s",fsnam); |
||
378 | |||
379 | fprintf(stderr,"reading nets from %s\n", argv[i]); |
||
380 | } |
||
381 | |||
382 | yyparse() ; |
||
383 | |||
384 | fclose(fo); |
||
385 | |||
386 | fprintf(stderr,"sorting...\n"); |
||
387 | sprintf(ln, "sort <%s >%s", fsnam, frnam); system(ln); |
||
388 | } |
||
389 | |||
390 | |||
391 | int |
||
392 | yylex() /* Gets the next token from the input stream */ |
||
393 | { |
||
394 | int c, i, j ; |
||
395 | static int eline ; |
||
396 | extern int bug; |
||
397 | |||
398 | start: |
||
399 | if(yysptr == -1){ |
||
400 | i = 0; eline =1; yylineno++; |
||
401 | /* get line to yysbuf */ |
||
402 | while( ((c=getchar()) != EOF) && (c != YYNL)){ |
||
403 | if(c == '\t'){ c=' ';do yysbuf[i++] = c; while(i & 7);} |
||
404 | else { |
||
405 | if (c != ' ')eline =0; |
||
406 | yysbuf[i++] = c; |
||
407 | } |
||
408 | } |
||
409 | yysptr = 0; |
||
410 | yysbuf[i] = '\0'; |
||
411 | yylast = toklast = 0; |
||
412 | } |
||
413 | if(c == EOF) |
||
414 | return(EOF); |
||
415 | |||
416 | while( (c = yysbuf[yysptr]) == ' ') yysptr++; |
||
417 | |||
418 | if(bug){ |
||
419 | fprintf(yyout,"%03d:%s\n",yylineno,yysbuf); |
||
420 | for( i=yysptr ; i>0 ; i-- )out(' '); |
||
421 | } |
||
422 | |||
423 | if ( c == YYNL || c== 0 ){ |
||
424 | yysptr= -1; |
||
425 | if(bug)fprintf(yyout,"\n"); |
||
426 | goto start; |
||
427 | } |
||
428 | |||
429 | if( comment ){ |
||
430 | while( (c = yysbuf[yysptr++]) != '*' && c != '/'&& c ); |
||
431 | if( c == '*' && yysbuf[yysptr]=='/' ) |
||
432 | comment-- ; |
||
433 | if( c == '/' && yysbuf[yysptr]=='*' ) |
||
434 | comment++ ; |
||
435 | if( c == 0 ) |
||
436 | yysptr = -1; |
||
437 | if( comment ) |
||
438 | goto start; |
||
439 | yysptr++; |
||
440 | goto start; |
||
441 | } |
||
442 | |||
443 | if( c == '/' ) { /* comment // ? */ |
||
444 | if( yysbuf[yysptr+1] == '/') { |
||
445 | yysptr= -1; |
||
446 | goto start; |
||
447 | } |
||
448 | if( yysbuf[yysptr+1] == '*') { |
||
449 | comment++; yysptr +=2; |
||
450 | goto start; |
||
451 | } |
||
452 | } |
||
453 | if( c == '\\'){ /* escaped name */ |
||
454 | yyleng=0; |
||
455 | while( (c=yysbuf[++yysptr]) != ' ' ) |
||
456 | yytext[yyleng++] = c; |
||
457 | yytext[yyleng] = '\0'; |
||
458 | if(bug)fprintf(yyout," ^tok:NAME\n"); |
||
459 | if( toklast==MODULE ){ |
||
460 | toklast = 0; |
||
461 | strcpy(modnam, yytext); |
||
462 | fprintf(stderr,"module %s\n", modnam); |
||
463 | } |
||
464 | if( toklast==PRIMITIVE ){ |
||
465 | toklast = 0; |
||
466 | strcpy(modnam, yytext); |
||
467 | fprintf(stderr,"primitive %s\n", modnam); |
||
468 | } |
||
469 | strcpy(yylval.s, yytext); |
||
470 | return(NAME); |
||
471 | } |
||
472 | if( isalpha(c) ) { |
||
473 | if( yylast == '\'' ){ /* number base - 1'b0 */ |
||
474 | yysptr++; |
||
475 | if(bug) |
||
476 | if(c < ' ') fprintf(yyout," ^CHAR:%d\n",c); |
||
477 | else fprintf(yyout," ^CHAR:%c\n",c); |
||
478 | yylast = c; |
||
479 | return(c); |
||
480 | } |
||
481 | if( (j=chktok()) != 0){ |
||
482 | toklast = j; |
||
483 | return(j); |
||
484 | } |
||
485 | name: |
||
486 | yyleng=0; |
||
487 | while( isalpha(c) || isdigit(c) || c=='_' ) { |
||
488 | yytext[yyleng++] = c; c = yysbuf[++yysptr]; |
||
489 | } |
||
490 | yytext[yyleng] = '\0'; |
||
491 | if(bug)fprintf(yyout," ^tok:NAME\n"); |
||
492 | if( toklast==MODULE ){ |
||
493 | toklast = 0; |
||
494 | strcpy(modnam, yytext); |
||
495 | fprintf(stderr,"module %s\n", modnam); |
||
496 | } |
||
497 | if( toklast==PRIMITIVE ){ |
||
498 | toklast = 0; |
||
499 | strcpy(modnam, yytext); |
||
500 | fprintf(stderr,"primitive %s\n", modnam); |
||
501 | } |
||
502 | strcpy(yylval.s, yytext); |
||
503 | return(NAME); |
||
504 | } |
||
505 | if( isdigit(c) ) { |
||
506 | yyleng=0; |
||
507 | while( isdigit(c) ) { |
||
508 | yytext[yyleng++] = c; c = yysbuf[++yysptr]; |
||
509 | } |
||
510 | yytext[yyleng] = '\0'; |
||
511 | if(bug)fprintf(yyout," ^tok:NUMBER\n"); |
||
512 | strcpy(yylval.s, yytext); |
||
513 | return(NUMBER); |
||
514 | } |
||
515 | yysptr++; yylast = c; |
||
516 | if( c=='+' || c=='-' || c=='&' || c=='|' || c=='^' ){ |
||
517 | if(bug) fprintf(yyout," ^BIN_OP:%c\n",c); |
||
518 | return(BIN_OP); |
||
519 | } |
||
520 | if( c=='!' || c=='~' ){ |
||
521 | if(bug) fprintf(yyout," ^UNARY_OP:%c\n",c); |
||
522 | return(UNARY_OP); |
||
523 | } |
||
524 | if(bug) |
||
525 | if(c < ' ') |
||
526 | fprintf(yyout," ^CHAR:%d\n",c); |
||
527 | else |
||
528 | fprintf(yyout," ^CHAR:%c\n",c); |
||
529 | return(c); |
||
530 | } /* nexttoken */ |
||
531 | |||
532 | int chktok() |
||
533 | { |
||
534 | static struct { char *keyword; int val, tok; } key [] = { |
||
535 | "module " , 0, MODULE, |
||
536 | "endmodule" , 0, ENDMODULE, |
||
537 | "primitive ", 0, PRIMITIVE, |
||
538 | "endprimitive",0,ENDPRIM, |
||
539 | "input " , 0, INPUT, |
||
540 | "output " , 0, OUTPUT, |
||
541 | "inout " , 0, INOUT, |
||
542 | "assign " , 0, ASSIGN, |
||
543 | "wire " , 0, NETTYPE, |
||
544 | "triand " , 1, NETTYPE, |
||
545 | "trior " , 2, NETTYPE, |
||
546 | "tri1 " , 3, NETTYPE, |
||
547 | "tri " , 4, NETTYPE, |
||
548 | "supply0 " , 5, NETTYPE, |
||
549 | "supply1 " , 6, NETTYPE, |
||
550 | "wor " , 7, NETTYPE, |
||
551 | "trireg " , 8, NETTYPE, |
||
552 | "supply0 " , 0, STRENGTH0, |
||
553 | "strong0 " , 1, STRENGTH0, |
||
554 | "pull0 " , 2, STRENGTH0, |
||
555 | "weak0 " , 3, STRENGTH0, |
||
556 | "highz0 " , 4, STRENGTH0, |
||
557 | "supply1 " , 0, STRENGTH1, |
||
558 | "strong1 " , 1, STRENGTH1, |
||
559 | "pull1 " , 2, STRENGTH1, |
||
560 | "weak1 " , 3, STRENGTH1, |
||
561 | "highz1 " , 4, STRENGTH1, |
||
562 | "parameter ", 0, PARAMETER, |
||
563 | "reg " , 0, REG, |
||
564 | "time " , 0, TIME, |
||
565 | "integer " , 0, INTEGER, |
||
566 | "real " , 0, REAL, |
||
567 | "event " , 0, EVENT, |
||
568 | "defparam " , 0, DEFPARAM, |
||
569 | "and " , 0, GATETYPE, |
||
570 | "nand " , 1, GATETYPE, |
||
571 | "or " , 2, GATETYPE, |
||
572 | "nor " , 3, GATETYPE, |
||
573 | "xor " , 4, GATETYPE, |
||
574 | "xnor " , 5, GATETYPE, |
||
575 | "buf " , 6, GATETYPE, |
||
576 | "tran " , 7, GATETYPE, |
||
577 | "table " , 0, TABLE, |
||
578 | "endtable" , 0, ENDTABLE, |
||
579 | "initial " , 0, INITIAL, |
||
580 | NULL, 0, 0 |
||
581 | }; |
||
582 | int save, i, j ; |
||
583 | char *s; |
||
584 | |||
585 | for( j=0 ; (s=key[j].keyword) != NULL ; j++) { |
||
586 | save = yysptr; yyleng = 0; |
||
587 | while( *s == yysbuf[yysptr++] && *s ) |
||
588 | yytext[yyleng++] = *s++; |
||
589 | if(*s == '\0'){ |
||
590 | yytext[yyleng] = '\0'; |
||
591 | yysptr--; |
||
592 | if(bug){ |
||
593 | for( i=yysptr-1 ; i>0 ; i-- )out(' '); |
||
594 | fprintf(yyout," ^tok:%s\n",yytext); |
||
595 | } |
||
596 | yylval.i = key[j].val; |
||
597 | return(key[j].tok); |
||
598 | } |
||
599 | yysptr = save; |
||
600 | } |
||
601 | return(0); |
||
602 | } |
||
603 | |||
604 | yyerror(s) |
||
605 | char *s; |
||
606 | { |
||
607 | int i; |
||
608 | |||
609 | fprintf(stderr,"%s error on line %d\n",s,yylineno); |
||
610 | fprintf(stderr,"%s\n", yysbuf); |
||
611 | for( i=yysptr ; i>0 ; i-- )out(' '); |
||
612 | fprintf(stderr,"^\n"); |
||
613 | } |
||
614 | |||
615 | char *strsave(s) |
||
616 | char *s; |
||
617 | { |
||
618 | char *p, *malloc(); |
||
619 | |||
620 | if((p = malloc(strlen(s)+1)) != NULL) strcpy(p,s); |
||
621 | if( p==NULL)err("out of malloc space"); |
||
622 | return(p); |
||
623 | } |
||
624 | |||
625 | err(s,t) |
||
626 | char *s,*t; |
||
627 | { |
||
628 | fprintf(stderr,s,t); fprintf(stderr,"\n"); |
||
629 | exit(1); |
||
630 | } |