|
|
1.1 root 1: %{
2: static char ID[] = "@(#) ld.yac: 1.8 12/1/83";
3: #include "system.h"
4: #include <stdio.h>
5: #include "bool.h"
6: #include "attributes.h"
7: #include "list.h"
8: #include "structs.h"
9:
10: #if TRVEC
11: #include "tv.h"
12: #include "ldtv.h"
13: #endif
14:
15: #include "extrns.h"
16: #include "sgs.h"
17: #include "sgsmacros.h"
18: #include "ldmacros.h"
19:
20:
21:
22: extern char inline[];
23:
24:
25: /*
26: *
27: * There is a very important variable, called
28: *
29: * in_y_exp
30: *
31: * that is used to help recognize filenames.
32: *
33: * The problems is this: a UNIX filename can contain
34: * virtually any character, and the nodes in the pathname
35: * are separated by slashes. Unfortunately, slashes also
36: * occur in expressions, comments, and the /= assignment
37: * operator. Moreover, the LEX rules ignore white space,
38: * which is important to knowing where one filename stops
39: * and the next begins.
40: *
41: * The resolution is this. Lex doesn't know enough alone to
42: * recognize a filename; so we give it some help. Whenever we
43: * are in an expression, we set in_y_exp to TRUE, and then lex knows
44: * that any slash is a slash, and should not be kept as part of
45: * a filename. a/b is a divided by b, not the file a/b.
46: *
47: * Consequently, whenever a slash must be kept as a slash,
48: * in_y_exp will be TRUE. Otherwise, it will be FALSE, and the
49: * lexical analyzer will treat a/b as a filename.
50: */
51:
52: int in_y_exp;
53:
54: static secnum; /* number of sections */
55: static char *fnamptr;
56: static int nsecspcs, fillflag; /* parsing status flags */
57: static ACTITEM *aiptr, *afaiptr, *grptr; /* pointers to action items */
58: extern char *curfilnm; /* name of current ifile */
59:
60: #if TRVEC
61: static TVASSIGN *tvslotn, /* ptr to last in list of tv slots */
62: *slotptr; /* temp for traversing list */
63: #endif
64:
65: static int tempi; /* temporary int */
66: /*eject*/
67: %}
68: /*eject*/
69: %token <sptr> NAME 2 /* ld directives and their component tokens */
70: %token <lptr> LONGINT 3
71: %token <ivalue> INT 4
72: %token <ivalue> ALIGN 5
73: %token <ivalue> DOT 6
74: %token <ivalue> LEN 7
75: %token <ivalue> MEMORY 8
76: %token <ivalue> ORG 9
77: %token <ivalue> REGIONS 10
78: %token <ivalue> SECTIONS 11
79: %token <ivalue> PHY 12
80:
81: %token <ivalue> AND 13 /* operators */
82: %token <ivalue> ANDAND 14
83: %token <ivalue> BNOT 15 /* bitwise NOT "~" */
84: %token <ivalue> COLON 16
85: %token <ivalue> COMMA 17
86: %token <ivalue> DIV 18
87: %token <ivalue> EQ 19
88: %token <ivalue> EQEQ 20
89: %token <ivalue> GE 21
90: %token <ivalue> GT 23
91: %token <ivalue> LBRACE 24
92: %token <ivalue> LE 26
93: %token <ivalue> LPAREN 27
94: %token <ivalue> LSHIFT 28
95: %token <ivalue> LT 29
96: %token <ivalue> MINUS 30
97: %token <ivalue> MULT 31
98: %token <ivalue> NE 32
99: %token <ivalue> NOT 33
100: %token <ivalue> OR 34
101: %token <ivalue> OROR 35
102: %token <ivalue> PC 36
103: %token <ivalue> PLUS 37
104: %token <ivalue> RBRACE 38
105: %token <ivalue> RPAREN 39
106: %token <ivalue> RSHIFT 40
107: %token <ivalue> SEMICOL 41
108: /* operator assignments */
109: %token <ivalue> DIVEQ 42
110: %token <ivalue> MINUSEQ 43
111: %token <ivalue> MULTEQ 44
112: %token <ivalue> PLUSEQ 45
113:
114: %token <sptr> FILENAME 46
115: %token <ivalue> TV 47
116: %token <ivalue> SPARE 48
117:
118: %token <ivalue> DSECT 49
119: %token <ivalue> NOLOAD 50
120: %token <ivalue> COPY 51
121: %token <ivalue> INFO 52
122:
123: %token <ivalue> BLOCK 53
124:
125: %token <ivalue> UMINUS 54
126: %token <ivalue> GROUP 55
127: %token <ivalue> RANGE 56
128: %token <ivalue> ASSIGN 57
129:
130:
131:
132:
133: %type <enode> assnment /* link value types with nonterminals */
134: %type <ivalue> assnop
135: %type <ivalue> attr
136: %type <enode> ename
137: %type <enode> expr
138: %type <sptr> filename
139: %type <ivalue> fillspc
140: %type <aitem> flgstmt2
141: %type <ivalue> inclspc
142: %type <ivalue> opt_attr
143: %type <lptr> opt_block
144: %type <lptr> opt_org
145: %type <lptr> opt_aln
146: %type <ivalue> opt_type
147: %type <enode> term
148: %type <lptr> vaddr
149:
150:
151:
152:
153: %right EQ PLUSEQ MINUSEQ MULTEQ DIVEQ
154: %left OROR
155: %left ANDAND
156: %left OR
157: %left AND
158: %binary EQEQ NE GT LT LE GE
159: %left LSHIFT RSHIFT
160: %left PLUS MINUS
161: %left MULT DIV PC
162: %right NOT BNOT
163: %left LPAREN
164:
165:
166:
167: %union {
168: int ivalue; /* yylval values */
169: char *sptr;
170: long *lptr;
171:
172: ACTITEM *aitem; /* nonterminal values */
173: ENODE *enode;
174: }
175: /*eject*/
176: %%
177:
178: wholefile: cmds = ;
179:
180: cmds: cmds cmd
181: | /* empty */
182: = ;
183:
184: cmd: regspecs
185: | memspecs
186: | tvspecs
187: | secspecs
188: | assnment = {
189: bldexp($1, &explist);
190: }
191: | filename = {
192: filespec($1);
193: }
194: | flagstmt
195: | error = {
196: for( tempi = lineno; tempi == lineno; )
197: yychar = yylex();
198: yyerrok;
199: yyclearin;
200: }
201: ;
202: /*eject*/
203: regspecs: REGIONS LBRACE reglist RBRACE = {
204: #if USEREGIONS == 0
205: yyerror("REGIONS command not allowed in a %s load", SGS);
206: #endif
207: }
208: ;
209:
210: reglist: rgnspc
211: | reglist rgnspc = ;
212:
213: rgnspc: NAME COLON ORG EQ LONGINT com LEN EQ LONGINT com vaddr = {
214: long *orgp, *lenp, *vaddrp, vzero;
215: REGION *rgnp;
216: orgp = $5;
217: lenp = $9;
218: if (*lenp <= 0)
219: yyerror("region %s has invalid length",$1);
220: if ( (vaddrp = $11) == NULL )
221: vzero = *orgp;
222: else
223: vzero = *orgp - *vaddrp;
224: if ( (vzero & 0xfL) != 0 ) {
225: yyerror("virtual 0 (paddr %.1lx) of region %s is not a multiple of 16",
226: vzero, $1);
227: vzero &= ~0xfL;
228: }
229: rgnp = (REGION *) myalloc(sizeof(REGION));
230: rgnp->rgorig = *orgp;
231: rgnp->rglength = *lenp;
232: rgnp->rgvaddr = (vaddrp == NULL) ? 0L : *vaddrp;
233: if( (rgnp->rgvaddr + rgnp->rglength) > 0x10000L ) {
234: yyerror("addresses of region %s (vaddr=%.1lx len=%.1lx) exceed 64K",
235: $1, rgnp->rgvaddr, *lenp);
236: rgnp->rglength = 0x10000L - rgnp->rgvaddr;
237: }
238: strncpy( rgnp->rgname, $1, 8 );
239: listadd(l_REG, ®list, rgnp);
240: }
241: | error = {
242: yyerror("REGIONS specification ignored");
243: }
244: ;
245:
246: com: COMMA
247: | /* empty */
248: = ;
249:
250: vaddr: DOT EQ LONGINT = {
251: if ( *(long *) $3 > 0xffffL ) {
252: yyerror("virtual address %.1lx exceeds 0xffff: truncated to %.1lx",
253: *(long *) $3, *(long *) $3 & 0xffffL);
254: *(long *) $3 &= 0xffffL;
255: }
256: $$ = $3;
257: }
258: | /* empty */
259: = {
260: $$ = NULL;
261: }
262: ;
263: /*eject*/
264: memspecs: MEMORY LBRACE memlist RBRACE =
265: ;
266:
267: memlist: memspc
268: | memlist memspc = ;
269:
270: memspc: NAME opt_attr COLON ORG EQ LONGINT com LEN EQ LONGINT com = {
271: long *orgp, *lenp;
272: MEMTYPE *memp;
273: orgp = $6;
274: lenp = $10;
275: memp = (MEMTYPE *) myalloc(sizeof(MEMTYPE));
276: memp->mtorig = *orgp;
277: memp->mtlength = *lenp;
278: memp->mtattr = $2;
279: strncpy( memp->mtname, $1, 8 );
280: listadd(l_MEM, &memlist, memp);
281: }
282: | error = {
283: yyerror("MEMORY specification ignored");
284: }
285: ;
286:
287: opt_attr: attr = {
288: $$ = $1;
289: }
290: | = { /* empty */
291: $$ = att_R | att_W | att_X | att_I;
292: }
293: ;
294:
295: attr: LPAREN NAME RPAREN = {
296: int attflgs;
297: char *p;
298: attflgs = 0;
299: for( p = $2; *p; p++ )
300: switch (*p) {
301: case 'R': attflgs |= att_R; break;
302: case 'W': attflgs |= att_W; break;
303: case 'X': attflgs |= att_X; break;
304: case 'I': attflgs |= att_I; break;
305: default: yyerror("bad attribute value in MEMORY directive: %c", *p);
306: }
307: $$ = attflgs;
308: }
309: ;
310: /*eject*/
311: tvspecs: TV opt_long LBRACE tvlist RBRACE tvfill = {
312: #if TRVEC
313: int length;
314:
315: tvspec.tvinflnm = curfilnm;
316: tvspec.tvinlnno = lineno;
317:
318: length = 0;
319: for( slotptr = tvslot1; slotptr != NULL; slotptr = slotptr->nxtslot ) {
320: TVASSIGN *slotptr2;
321: length = max(length, slotptr->slot);
322: for (slotptr2 = tvslot1; slotptr2 != slotptr; slotptr2 = slotptr2->nxtslot )
323: if (slotptr2->slot == slotptr->slot) {
324: lderror(1,0,NULL,
325: "function %s assigned to tv slot %d which is already in use", slotptr->funname, slotptr->slot);
326: break;
327: }
328: }
329: if( tvspec.tvlength > 0 ) {
330: if( length > tvspec.tvlength ) {
331: yyerror("ASSIGN slot %d exceeds total TV size of %d",
332: length, tvspec.tvlength);
333: tvspec.tvlength = length;
334: }
335: if( tvspec.tvrange[1] > tvspec.tvlength ) {
336: yyerror("RANGE value %d exceeds total TV size of %d",
337: tvspec.tvrange[1], tvspec.tvlength);
338: tvspec.tvlength = tvspec.tvrange[1];
339: }
340: }
341: else
342: tvspec.tvlength = max(length, tvspec.tvrange[1]);
343: #else
344: yyerror("usage of unimplemented syntax");
345: #endif
346: }
347: ;
348:
349: tvlist: SPARE EQ LONGINT = {
350: #if TRVEC
351: tvspec.tvosptr = (OUTSECT *) ((unsigned) *(long *) $3);
352: #else
353: yyerror("usage of unimplemented syntax");
354: #endif
355: }
356: | tvdirlist
357: ;
358:
359: tvdirlist: tvdir tvdirlist
360: | /* empty */
361: ;
362:
363: tvdir: LEN EQ LONGINT = {
364: #if TRVEC
365: if( tvspec.tvlength > 0 )
366: yyerror("illegal multiple LENGTH fields in the TV directive");
367: tvspec.tvlength = (int) (*(long *) $3);
368: #else
369: yyerror("usage of unimplemented syntax");
370: #endif
371: }
372: | RANGE LPAREN LONGINT COMMA LONGINT RPAREN = {
373: #if TRVEC
374: if( tvspec.tvrange[1] > 0 )
375: yyerror("illegal multiple RANGE fields in the TV directive");
376: if( tvspec.tvrange[0] < 0 || tvspec.tvrange[0] > tvspec.tvrange[1] )
377: yyerror("illegal RANGE syntax: r[0]<0 or r[0]>r[1]");
378: else {
379: tvspec.tvrange[0] = (int) (*(long *) $3);
380: tvspec.tvrange[1] = (int) (*(long *) $5);
381: }
382: #else
383: yyerror("usage of unimplemented syntax");
384: #endif
385: }
386: | ASSIGN LPAREN slotlist RPAREN
387: ;
388:
389: tvfill : EQ NAME = {
390: #if TRVEC
391: #if FLEXNAMES
392: tvspec.tvfnfill = savefn($2);
393: #else
394: strncpy(tvspec.tvfnfill, $2, 8 );
395: #endif
396: #else
397: yyerror("usage of unimplemented syntax");
398: #endif
399: }
400: | /* empty */
401: ;
402:
403: slotlist: slotspec
404: | slotlist com slotspec
405: | /* empty */
406: ;
407: slotspec: NAME EQ LONGINT = {
408: #if TRVEC
409: if( (int) (*(long *) $3) == 0 )
410: yyerror("illegal ASSIGN slot number (0)");
411: if( tvslot1 == NULL )
412: tvslot1 = tvslotn = (TVASSIGN *) myalloc(sizeof(TVASSIGN));
413: else
414: tvslotn = tvslotn->nxtslot = (TVASSIGN *) myalloc(sizeof(TVASSIGN));
415: #if FLEXNAMES
416: tvslotn->funname = savefn($1);
417: #else
418: strncpy(tvslotn->funname, $1, 8);
419: #endif
420: tvslotn->slot = (int) (*(long *) $3);
421: tvslotn->nxtslot = NULL;
422: #else
423: yyerror("usage of unimplemented syntax");
424: #endif
425: }
426: ;
427:
428: opt_long : LONGINT = {
429: long org;
430: org = *(long *) $1;
431: #if TRVEC
432: chktvorg(org, &(tvspec.tvbndadr));
433: #endif
434: }
435: | /* empty */
436: ;
437: /*eject*/
438: secspecs: SECTIONS LBRACE sglist RBRACE =
439: ;
440:
441: sglist: sec_or_grp
442: | sglist com sec_or_grp
443: ;
444:
445: sec_or_grp: scnspc
446: | groupspc
447: | flgstmt2
448: ;
449:
450: seclist: scnspc
451: | seclist com scnspc
452: ;
453:
454: groupspc: grprfx LBRACE seclist RBRACE inclspc = {
455: listadd(l_AI,&bldoutsc,grptr);
456: grptr = NULL;
457: }
458: ;
459:
460: grprfx: GROUP opt_org opt_aln opt_block COLON = {
461: if ( $2 != NULL && $3 != NULL )
462: yyerror("bonding excludes alignment");
463: grptr = dfnscngrp(AIDFNGRP, (long *)$2, (long *)$3, (long *)$4);
464: strncpy( grptr->dfnscn.ainame, "*group*", 8 );
465: }
466: ;
467:
468: flgstmt2: MINUS NAME = {
469: char *fp;
470: fp = $2;
471: if (fp[0] == 'l') /* library flag */
472: library(fp);
473: else
474: yyerror("bad flag value in SECTIONS directive: -%s", $2);
475: }
476: ;
477:
478: scnspc: scnprfx LBRACE scnstmts RBRACE fillspc inclspc = {
479: if (aiptr == NULL)
480: goto scnerr;
481: aiptr->dfnscn.aifill = $5;
482: aiptr->dfnscn.aifillfg = fillflag;
483: listadd(l_AI,grptr ? &grptr->dfnscn.sectspec : &bldoutsc,aiptr);
484: if (grptr && $6)
485: yyerror("can not specify an owner for section within a group");
486: aiptr = NULL;
487: }
488: | error = {
489: if (aiptr)
490: yyerror("section %s not built", aiptr->dfnscn.ainame);
491: scnerr:
492: aiptr = NULL;
493: }
494: ;
495:
496: scnprfx: NAME opt_org opt_aln opt_block opt_type COLON = {
497: secnum++;
498: if ( OKSCNNAME($1) == 0 )
499: yyerror("%s is a reserved section name", $1);
500: if ( $2 != NULL && $3 != NULL )
501: yyerror("bonding excludes alignment");
502: aiptr = dfnscngrp(AIDFNSCN, (long *)$2, (long *)$3, (long *)$4);
503: if (grptr && aiptr->dfnscn.aibndadr != -1L)
504: yyerror("can not bond a section within a group");
505: if (grptr && aiptr->dfnscn.aialign != 0L)
506: yyerror("can not align a section within a group");
507: aiptr->dfnscn.aisctype = $5;
508: strncpy( aiptr->dfnscn.ainame, $1, 8 );
509: }
510: ;
511:
512: opt_block: BLOCK LPAREN LONGINT RPAREN = {
513: $$ = $3;
514: }
515: | = { /* empty */
516: $$ = NULL;
517: }
518: ;
519:
520: opt_org: LONGINT = {
521: $$ = $1;
522: }
523: | = { /* empty */
524: $$ = NULL;
525: }
526: ;
527:
528: opt_aln: ALIGN LPAREN LONGINT RPAREN = {
529: $$ = $3;
530: }
531: | = { /* empty */
532: $$ = NULL;
533: }
534: ;
535:
536: opt_type: LPAREN DSECT RPAREN = {
537: $$ = STYP_DSECT;
538: }
539: | LPAREN NOLOAD RPAREN = {
540: $$ = STYP_NOLOAD;
541: }
542: | LPAREN COPY RPAREN = {
543: $$ = STYP_COPY | STYP_DSECT;
544: }
545: | LPAREN INFO RPAREN = {
546: $$ = STYP_INFO | STYP_DSECT;
547: }
548: | = { /* empty */
549: $$ = STYP_REG;
550: }
551: ;
552:
553: scnstmts: scnstmt
554: | scnstmts com scnstmt
555: | /* empty */
556: ;
557:
558: scnstmt: fname insecspc
559: | flgstmt2 = {
560: bldadfil( ((ACTITEM *) ldfilist.tail)->ldlbry.aifilnam, aiptr );
561: }
562: | assnment = {
563: bldexp($1,&aiptr->dfnscn.sectspec);
564: }
565: | error = {
566: in_y_exp = 0;
567: yyerror("statement ignored");
568: for( tempi = lineno; ((int)yychar > 0) && (tempi == lineno) ; )
569: yychar = yylex();
570: if ((int) yychar <= 0)
571: lderror(2,0,NULL, "unexpected EOF");
572: yyerrok;
573: yyclearin;
574: }
575: ;
576:
577: fname: filename = {
578: fnamptr = savefn($1);
579: nsecspcs = 0;
580: bldldfil(fnamptr,0);
581: afaiptr = bldadfil(fnamptr,aiptr);
582: }
583: ;
584: insecspc: LPAREN inseclist RPAREN fillspc = {
585: afaiptr->adfile.ainadscs = nsecspcs;
586: afaiptr->adfile.aifilflg = fillflag;
587: afaiptr->adfile.aifill2 = $4;
588: }
589: | /* empty */
590: ;
591:
592: inseclist: NAME = {
593: nsecspcs++;
594: bldadscn($1,fnamptr,aiptr);
595: }
596: | inseclist com NAME = {
597: nsecspcs++;
598: bldadscn($3,fnamptr,aiptr);
599: }
600: ;
601:
602: inclspc: GT NAME = {
603: if (grptr)
604: strncpy( grptr->dfnscn.aiowname, $2, 8 );
605: else
606: strncpy( aiptr->dfnscn.aiowname, $2, 8 );
607: $$ = 1;
608: }
609: | GT attr = {
610: if (grptr)
611: grptr->dfnscn.aiattown = $2;
612: else
613: aiptr->dfnscn.aiattown = $2;
614: $$ = 1;
615: }
616: | = { /* empty */
617: $$ = 0;
618: }
619: ;
620:
621: fillspc: EQ LONGINT = {
622: fillflag = 1;
623: $$ = (int) (*(long *)$2);
624: }
625: | = { /* empty */
626: fillflag = 0;
627: $$ = 0;
628: }
629: | EQ error = {
630: yyerror("bad fill value");
631: fillflag = 0;
632: yyerrok;
633: yyclearin;
634: $$ = 0;
635: }
636: ;
637: /*eject*/
638: assnment: ename assnop expr exend = {
639: in_y_exp = 0;
640: if ( $2 == EQ )
641: $$ = buildtree(EQ, $1, $3);
642: else {
643: ENODE *p,*ndp;
644: ndp = buildtree($2,$1,$3);
645: p = (ENODE *) myalloc(sizeof(ENODE));
646: *p = *$1;
647: $$ = buildtree(EQ,p,ndp);
648: }
649: }
650: ;
651:
652: assnop: DIVEQ = { $$ = DIV; in_y_exp = TRUE; }
653: | EQ = { $$ = EQ; in_y_exp = TRUE; }
654: | MINUSEQ = { $$ = MINUS; in_y_exp = TRUE; }
655: | MULTEQ = { $$ = MULT; in_y_exp = TRUE; }
656: | PLUSEQ = { $$ = PLUS; in_y_exp = TRUE; }
657: ;
658:
659: expr: expr PLUS expr = {
660: bop:
661: $$ = buildtree($2,$1,$3);
662: }
663: | expr MINUS expr = { goto bop; }
664: | expr MULT expr = { goto bop; }
665: | expr DIV expr = { goto bop; }
666: | expr PC expr = { goto bop; }
667: | expr RSHIFT expr = { goto bop; }
668: | expr LSHIFT expr = { goto bop; }
669: | expr AND expr = { goto bop; }
670: | expr OR expr = { goto bop; }
671: | expr GT expr = { goto bop; }
672: | expr LT expr = { goto bop; }
673: | expr GE expr = { goto bop; }
674: | expr LE expr = { goto bop; }
675: | expr NE expr = { goto bop; }
676: | expr EQEQ expr = { goto bop; }
677: | expr ANDAND expr = { goto bop; }
678: | expr OROR expr = { goto bop; }
679: | term = {
680: $$ = $1;
681: }
682: ;
683:
684: exend: SEMICOL
685: | COMMA
686: | error = {
687: yyerror ("semicolon required after expression");
688: }
689: ;
690:
691: term: LONGINT = {
692: $$ = cnstnode(*(long *) $1);
693: }
694: | ename = {
695: $$ = $1;
696: }
697: | MINUS term = {
698: $$ = buildtree(UMINUS,$2,NULL);
699: }
700: | NOT term = {
701: $$ = buildtree($1,$2,NULL);
702: }
703: | BNOT term = {
704: $$ = buildtree(BNOT,$1,NULL);
705: }
706: | ALIGN LPAREN expr RPAREN = {
707: $$ = buildtree($1,$3,NULL);
708: }
709: | PHY LPAREN ename RPAREN = {
710: $$ = buildtree($1,$3,NULL);
711: }
712: | LPAREN expr RPAREN = {
713: $$ = $2;
714: }
715: ;
716:
717: ename: NAME = {
718: $$ = symnode($1);
719: }
720: | DOT = {
721: $$ = symnode(NULL);
722: }
723: ;
724: /*eject*/
725: filename: NAME = {
726: $$ = $1;
727: }
728: | FILENAME = {
729: $$ = $1;
730: }
731: ;
732: /*eject*/
733: flagstmt: MINUS filename = {
734: pflags($2, TRUE);
735: }
736: ;
737: %%
738: /*eject*/
739: /*VARARGS*/
740: yyerror(format, a1, a2, a3, a4)
741: char *format;
742: {
743:
744: /*
745: * Issue a parsing error message
746: */
747:
748: char *p;
749:
750: p = sname(curfilnm); /* strip off directories from path name */
751:
752: /*
753: * For any purely YACC-generated error, also print out the current
754: * line, up to the point of the error
755: */
756:
757: if( strcmp(format, "syntax error") == 0 )
758: lderror(1, lineno, p, "%s : scanned line = (%s)", format, inline, a1, a2 );
759: else
760: lderror(1, lineno, p, format, a1, a2, a3, a4);
761: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.