OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [sw/] [zasm/] [zasm.y] - Blame information for rev 34

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 13 dgisselq
/*******************************************************************************
2
**
3
** Filename:    zasm.y
4
**
5
** Project:     Zip CPU -- a small, lightweight, RISC CPU core
6
**
7
** Purpose:     The parser for the Zip Assembler.  This is actually not just
8
**              the parser, but the main program as well.
9
**
10
** Creator:     Dan Gisselquist, Ph.D.
11
**              Gisselquist Tecnology, LLC
12
**
13
********************************************************************************
14
**
15
** Copyright (C) 2015, Gisselquist Technology, LLC
16
**
17
** This program is free software (firmware): you can redistribute it and/or
18
** modify it under the terms of  the GNU General Public License as published
19
** by the Free Software Foundation, either version 3 of the License, or (at
20
** your option) any later version.
21
**
22
** This program is distributed in the hope that it will be useful, but WITHOUT
23
** ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24
** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25
** for more details.
26
**
27
** You should have received a copy of the GNU General Public License along
28
** with this program.  (It's in the $(ROOT)/doc directory, run make with no
29
** target there if the PDF file isn't present.)  If not, see
30
**  for a copy.
31
**
32
** License:     GPL, v3, as defined and found on www.gnu.org,
33
**              http://www.gnu.org/licenses/gpl.html
34
**
35
**
36
*******************************************************************************/
37
 
38
%{
39
 #include 
40
 #include 
41
 #include "asmdata.h"
42
 
43 26 dgisselq
#define DEFAULT_OUTPUT_FNAME    "z.out"
44
#define YYDEBUG 1
45
 
46 13 dgisselq
  extern "C" int yylex(void);
47
  extern "C" int yyparse(void);
48
  // extern "C" FILE *yyin;
49
  void yyerror(const char *);
50
  unsigned int global_parser_pc;
51
  char *master_input_filename = NULL;
52
  extern int yylineno;
53
  char  *linecp = NULL; // A copy of the input line
54
%}
55
 
56
%token COMMA EQU PLUS MINUS TIMES HERE DOLLAR COLON
57
%token BOOLEANOR BITWISEOR BOOLEANAND BITWISEAND BITWISEXOR DOT
58
%token WORD FILL
59
%token LOADOP STOROP LDIOP
60
%token BAREOP BRANCHOP COND DUALOP IDENTIFIER INT LDHLOP REG SINGLOP
61
 
62
%union {
63
        ZPARSER::ZIPREG         u_reg;
64
        ZPARSER::ZIPCOND        u_cond;
65
        int                     u_ival;
66
        LEXOPCODE               u_op;
67
        char                    *u_id;
68
        ASMLINE                 *u_ln;
69
        AST                     *u_ast;
70
}
71
 
72
%type                   REG
73
%type           COND opcond
74
%type           INT
75
%type                   IDENTIFIER
76
%type                   BAREOP SINGLOP DUALOP BRANCHOP LDHLOP
77
%type                   unlabeledline instruction wordlist fillist opb
78
%type                   bareop singlop dualop loadop storop line
79
%type                   expr value multident
80
 
81 26 dgisselq
%left BOOLEANOR
82
%left BOOLEANAND
83
%left BITWISEOR BITWISEXOR
84
%left BITWISEAND
85 34 dgisselq
%left '%'
86 26 dgisselq
%left PLUS MINUS
87
%left TIMES '/'
88
 
89 13 dgisselq
%% /* The grammar follows */
90
 
91
input:
92
  %empty
93
| input line { if ($2) {objcode += $2; global_parser_pc += $2->nlines(); if ($2->isdefined()) delete $2; } }
94
;
95
 
96
line:
97
   '\n' { $$ = NULL; }
98
| unlabeledline '\n' { $$ = $1; }
99
| multident COLON unlabeledline '\n' {
100
        if ($1->m_node_type == 'I') {
101
                if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
102
                        stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
103
                else
104
                        gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
105
                delete $1;
106
                }
107
        $$ = $3;
108
        }
109
| multident COLON '\n' {
110
        if ($1->m_node_type == 'I') {
111
                if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
112
                        stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
113
                else
114
                        gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
115
                delete $1;
116
        }
117
        $$ = new VLINE();
118
        }
119
| multident EQU expr '\n' {
120
        if ($1->m_node_type == 'I') {
121
                stb_define(((AST_IDENTIFIER *)$1)->m_id, $3);
122
                delete $1;
123
        }
124
        $$ = new VLINE();
125
        }
126
;
127
 
128
unlabeledline:
129
  instruction   { $$ = $1; }
130
| WORD wordlist { $$ = $2; }
131
| FILL fillist { $$ = $2; }
132
;
133
 
134
wordlist:
135
  expr  {
136
        if ($1->isdefined())
137
                $$ = new DLINE($1->eval());
138
        else {
139
                $$ = new VLINE();
140
                yyerror("ERROR: word list undefined");
141
        }}
142 16 dgisselq
| wordlist COMMA expr {
143
        if ($3->isdefined()) {
144
                LLINE   *ln;
145
                if ($1->m_state == 'L') {
146
                        ln = ((LLINE *)$1);
147
                } else {
148
                        ln = new LLINE();
149
                        ln->addline($1);
150
                } ln->addline(new DLINE($3->eval()));
151
                $$ = ln;
152
        } else {
153 13 dgisselq
                $$ = new VLINE();
154
                yyerror("ERROR: word list undefined\n");
155
        }}
156
;
157
 
158
fillist:
159
  expr COMMA expr {
160
                if (($1->isdefined())&&($3->isdefined())) {
161
                        int     ntimes = $1->eval(),
162
                                val = $3->eval();
163
                        LLINE   *ln = new LLINE();
164
                        for(int i=0; i
165
                                ln->addline(new DLINE(val));
166
                        $$ = ln;
167
                } else {
168
                        yyerror("Fill list undefined\n");
169
                        $$ = new VLINE();
170
                }
171
        }
172
;
173
 
174
instruction:
175
  dualop  opb COMMA REG {
176
                $$ = $1;
177
                ((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
178
                ((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
179
                ((TLINE*)$1)->m_opa = $4;
180
                if ($1->isdefined()) {
181
                        $$ = ((TLINE*)$1)->eval();
182
                        delete $1;
183
                        delete $2;
184
                }
185
        }
186
| dualop  opb COMMA multident {
187
                char    buf[256];
188
                sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
189
                yyerror(buf);
190
                $$ = new VLINE();
191
                delete $1;
192
                delete $2;
193
                delete $4;
194
        }
195
| singlop opb   {
196
                $$ = $1;
197
                ((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
198
                ((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
199
                if ($1->isdefined()) {
200
                        $$ = ((TLINE *)$1)->eval();
201
                        delete $1;
202
                }
203
        }
204
| bareop        { $$ = $1; }
205
| LDHLOP  opcond expr COMMA REG {
206
                TLINE *tln = new TLINE;
207
                tln->m_opcode = $1;
208
                tln->m_cond   = $2;
209
                tln->m_imm    = $3;
210
                tln->m_opa    = $5;
211
 
212
                if (tln->isdefined()) {
213
                        $$ = tln->eval();
214
                        delete tln;
215
                } else
216
                        $$ = tln;
217
        }
218
| LDHLOP  opcond expr COMMA multident {
219
                char    buf[256];
220
                sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$5)->m_id.c_str());
221
                yyerror(buf);
222
                $$ = new VLINE();
223
                delete $3;
224
                delete $5;
225
        }
226
| LDIOP          expr COMMA REG {
227
                TLINE *tln = new TLINE;
228
                tln->m_opcode = OP_LDI;
229
                tln->m_cond   = ZPARSER::ZIPC_ALWAYS;
230
                tln->m_imm    = $2;
231
                tln->m_opa    = $4;
232
 
233
                if (tln->isdefined()) {
234
                        $$ = tln->eval();
235
                        delete tln;
236
                } else
237
                        $$ = tln;
238
        }
239
| LDIOP  expr COMMA multident {
240
                char    buf[256];
241
                sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
242
                yyerror(buf);
243
                $$ = new VLINE();
244
                delete $2;
245
                delete $4;
246
        }
247
| BRANCHOP  expr        {
248
                TLINE *tln = new TLINE;
249
                tln->m_opcode = $1;
250
                tln->m_imm    = $2;
251
 
252
                if (tln->isdefined()) {
253
                        $$ = tln->eval();
254
                        delete tln;
255
                } else
256
                        $$ = tln;
257
        }
258
| loadop opb COMMA REG {
259
                TLINE *tln = new TLINE;
260
                ((TLINE*)$2)->m_opcode = OP_LOD;
261
                ((TLINE*)$2)->m_cond   = ((TLINE*)$1)->m_cond;
262
                ((TLINE*)$2)->m_opa    = $4;
263
 
264
                delete $1;
265
 
266
                if (((TLINE *)$2)->isdefined()) {
267
                        $$ = ((TLINE *)$2)->eval();
268
                        delete $2;
269
                } else
270
                        $$ = $2;
271
        }
272
| loadop opb COMMA multident {
273
                char    buf[256];
274
                sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
275
                yyerror(buf);
276
                $$ = new VLINE();
277
                delete $1;
278
                delete $2;
279
                delete $4;
280
        }
281
| storop REG COMMA opb {
282
                TLINE *tln = new TLINE;
283
                tln->m_opcode = OP_STO;
284
                tln->m_cond   = ((TLINE*)$1)->m_cond;
285
                tln->m_imm    = ((TLINE*)$4)->m_imm;
286
                tln->m_opb    = ((TLINE*)$4)->m_opb;
287
                tln->m_opa    = $2;
288
 
289
                delete $1;
290
 
291
                if (tln->isdefined()) {
292
                        $$ = tln->eval();
293
                        delete tln;
294
                } else
295
                        $$ = tln;
296
        }
297
| storop multident COMMA opb {
298
                char    buf[256];
299
                sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$2)->m_id.c_str());
300
                yyerror(buf);
301
                $$ = new VLINE();
302
                delete $1;
303
                delete $2;
304
                delete $4;
305
        }
306
;
307
 
308
dualop: DUALOP  opcond {
309
        TLINE *tln = new TLINE();
310
        tln->m_opcode = $1;
311
        tln->m_cond   = $2;
312
        $$ = tln;
313
        }
314
;
315
 
316
singlop: SINGLOP opcond {
317
        TLINE *tln = new TLINE();
318
        tln->m_opcode = $1;
319
        tln->m_cond   = $2;
320
        $$ = tln;
321
        }
322
;
323
 
324
storop: STOROP opcond {
325
        TLINE *tln = new TLINE();
326
        tln->m_opcode = OP_STO;
327
        tln->m_cond   = $2;
328
        $$ = tln;
329
        }
330
;
331
 
332
loadop: LOADOP opcond {
333
        TLINE *tln = new TLINE();
334
        tln->m_opcode = OP_LOD;
335
        tln->m_cond   = $2;
336
        $$ = tln;
337
        }
338
;
339
 
340
bareop: BAREOP  opcond {
341
        TLINE *tln = new TLINE();
342
        tln->m_opcode = $1;
343
        tln->m_cond   = $2;
344
        $$ = tln;
345
        }
346
;
347
 
348
opcond:
349
        COND    { $$ = $1; }
350
|       %empty  { $$ = ZPARSER::ZIPC_ALWAYS; }
351
;
352
 
353
opb:
354
        expr    {
355
                TLINE *tln = new TLINE();
356
                tln->m_imm = $1;
357
                $$ = tln;
358
        }
359
|       expr PLUS REG {
360
                TLINE *tln = new TLINE();
361
                tln->m_imm = $1;
362
                tln->m_opb = $3;
363
                $$ = tln;
364
        }
365
|       expr '(' REG ')' {
366
                TLINE *tln = new TLINE();
367
                tln->m_imm = $1;
368
                tln->m_opb = $3;
369
                $$ = tln;
370
        }
371
|       '(' REG ')' {
372
                TLINE *tln = new TLINE();
373
                tln->m_imm = new AST_NUMBER(0);
374
                tln->m_opb = $2;
375
                $$ = tln;
376
        }
377
|       REG {
378
                TLINE *tln = new TLINE();
379
                tln->m_imm = new AST_NUMBER(0);
380
                tln->m_opb = $1;
381
                $$ = tln;
382
        }
383
;
384
 
385
expr:
386
        value                   { $$ = $1; }
387 34 dgisselq
|       MINUS value %prec TIMES  { $$ = new AST_BRANCH('-',new AST_NUMBER(0), $2); }
388
|       expr PLUS expr          { $$ = new AST_BRANCH('+',$1,$3); }
389
|       expr MINUS expr         { $$ = new AST_BRANCH('-',$1,$3); }
390
|       expr TIMES expr         { $$ = new AST_BRANCH('*',$1,$3); }
391
|       expr '/' expr           { $$ = new AST_BRANCH('/',$1,$3); }
392
|       expr '%' expr           { $$ = new AST_BRANCH('%',$1,$3); }
393
|       expr BOOLEANOR expr     { $$ = new AST_BRANCH('o',$1,$3); }
394
|       expr BITWISEOR expr     { $$ = new AST_BRANCH('|',$1,$3); }
395
|       expr BOOLEANAND expr    { $$ = new AST_BRANCH('a',$1,$3); }
396
|       expr BITWISEAND expr    { $$ = new AST_BRANCH('&',$1,$3); }
397
|       expr BITWISEXOR expr    { $$ = new AST_BRANCH('^',$1,$3); }
398 13 dgisselq
|       '(' expr ')'            { $$ = $2; }
399
;
400
        /* expr OR  (|) value */
401
        /* expr XOR (^) value */
402
        /* expr AND (&) value */
403
 
404
value:
405
        INT     { $$ = new AST_NUMBER($1); }
406
| multident     { $$ = $1; }
407
| HERE          { $$ = new AST_NUMBER(global_parser_pc); }
408
;
409
 
410
multident:
411
        IDENTIFIER              { $$ = new AST_IDENTIFIER($1); delete $1; }
412
| multident DOT IDENTIFIER      { $$ = new AST_IDENTIFIER($1,$3); delete $3; }
413
;
414
%%
415
 
416
#include 
417
#include 
418 26 dgisselq
#include 
419 13 dgisselq
#include 
420
#include 
421
#include 
422
 
423
OBJFILE objcode;
424
 
425
void    yyerror(const char *str) {
426
        fprintf(stderr, "%s:%d: ERROR: %s\n", master_input_filename, yylineno, str);
427
        if (linecp) fprintf(stderr, "Offending line was: %s\n", linecp);
428
}
429
 
430 26 dgisselq
FILE    *run_preprocessor(pid_t &pid, const char *path = NULL, const char *zname = NULL) {
431 13 dgisselq
        int     pipefd[2];
432
 
433
        if (pipe(pipefd)!=0) {
434
                fprintf(stderr, "PIPE FAILED!\n");
435
                perror("O/S Err:");
436
                exit(-2);
437
        } if ((zname)&&(access(zname, R_OK)!=0)) { // if !zname, then use stdin
438
                fprintf(stderr, "Cannot open %s\n", zname);
439
                perror("O/S Err:");
440
                exit(-2);
441
        }
442
 
443
 
444
        if (0 == (pid = fork())) {
445
                int     fdin, fdout;
446
 
447
                // Child process -- run the preprocessor
448
 
449 16 dgisselq
                // Close the reader: we write only
450 13 dgisselq
                close(pipefd[0]);
451
 
452 16 dgisselq
                // Adjust stdout to write to our pipe instead of anywhere else
453 13 dgisselq
                fdout = pipefd[1];
454
                close(STDOUT_FILENO);
455
                dup2(fdout, STDOUT_FILENO);
456
 
457 16 dgisselq
                char    *zpp_path;
458
                if (path != NULL) {
459
                        zpp_path = new char[strlen(path+1+strlen("/zpp"))];
460
                        strcpy(zpp_path, path);
461
                        strcat(zpp_path, "/zpp");
462
                } else zpp_path = strdup("zpp");
463
 
464 13 dgisselq
                // This call should never return
465 16 dgisselq
                //      We have to pass the name here, rather than an open file,
466
                // since zpp needs to mark for us what file it is in at all
467
                // times.
468
                if (zname)
469
                        execlp(zpp_path, "zpp", zname, NULL);
470
                else
471
                        execlp(zpp_path, "zpp", NULL);
472 13 dgisselq
 
473
                fprintf(stderr, "Could not start pre-processor!\n");
474
                perror("O/S Err:");
475
 
476
                exit(-5);
477
        }
478
 
479
        close(pipefd[1]);
480
        return fdopen(pipefd[0], "r");
481
}
482
 
483 26 dgisselq
void    usage(void) {
484
        printf("USAGE: zasm [-h] [-d] [-E] [-o ]  [ ]* ...\n");
485
        printf("\t-d\tTurns on debugging in the parser\n");
486
        printf("\t-E\tProduces preprocessor output only\n");
487
        printf("\t-h\tDisplays this message\n");
488
        printf("\t-o \tWrites the output to .  The\n"
489
                "\t\tdefault output file is \"" DEFAULT_OUTPUT_FNAME "\".\n");
490
 
491
        printf("\t-I \tSearch  for include files.\n");
492
}
493
 
494 13 dgisselq
int     main(int argc, char **argv) {
495
        int     skp = 0;
496
        const char      *zout_fname = NULL;
497 16 dgisselq
        char            *path_to_zasm = NULL;
498
        bool    preprocess_only = false;
499 26 dgisselq
        FILE            *ppout;
500
        pid_t           zpp_pid;
501
        int             zpp_status;
502
 
503 13 dgisselq
        master_input_filename = NULL;
504
 
505 16 dgisselq
        // Find what directory zasm is in, so that we can find zpp when
506
        // necessary.
507
        path_to_zasm = NULL;
508
        if (strchr(argv[0], '/')) {
509
                path_to_zasm = strdup(argv[0]);
510
                char *ptr = strrchr(path_to_zasm,'/');
511
                *ptr = '\0';
512
        }
513
 
514 13 dgisselq
        skp=1;
515
        for(int argn=0; argn+skp
516
                if (argv[argn+skp][0] == '-') {
517
                        if (argv[argn+skp][1] == 'o') {
518
                                if (zout_fname)
519
                                        free((void *)zout_fname);
520
                                zout_fname = strdup(argv[argn+skp+1]);
521
                                skp++;
522 16 dgisselq
                        } else if (argv[argn+skp][1] == 'E')
523
                                preprocess_only = true;
524 26 dgisselq
                        else if (argv[argn+skp][1] == 'd')
525
                                yydebug = 1;
526
                        else if (argv[argn+skp][1] == 'h') {
527
                                usage();
528
                                exit(0);
529
                        }
530 13 dgisselq
 
531
                        skp++;
532
                } argv[argn] = argv[argn+skp];
533
        } argc -= skp;
534
 
535 26 dgisselq
        if (zout_fname) {
536
                for(int argn=0; argn
537
                        if (strcmp(zout_fname, argv[argn])==0) {
538
                                fprintf(stderr, "ERR: Cowardly refusing to overwrite \'%s\'\n", zout_fname);
539
                                exit(-2);
540
                        }
541
                }
542
        }
543
 
544 16 dgisselq
        if (preprocess_only) {
545
                objcode.open("/dev/null");
546 26 dgisselq
                if (zout_fname)
547
                        ppout = fopen(zout_fname, "w");
548
                else
549
                        ppout = stdout;
550 16 dgisselq
        } else {
551
                if (!zout_fname)
552 26 dgisselq
                        zout_fname = DEFAULT_OUTPUT_FNAME;
553 13 dgisselq
 
554 16 dgisselq
                objcode.open(zout_fname);
555
        }
556 13 dgisselq
 
557
        master_input_filename = NULL;
558
 
559
        if (argc > 0) {
560
                for(int argn=0; argn
561
                        extern  FILE    *yyin;
562
                        extern  void    yyrestart(FILE *);
563
                        FILE    *tst;
564
 
565
                        create_new_context();
566
                        if (master_input_filename)
567
                                free(master_input_filename);
568
                        master_input_filename = strdup(argv[argn]);
569 16 dgisselq
                        if (preprocess_only) {
570 26 dgisselq
                                FILE    *fp = run_preprocessor(zpp_pid, path_to_zasm, master_input_filename);
571 16 dgisselq
                                int     ch;
572
                                while(EOF != (ch = fgetc(fp)))
573 26 dgisselq
                                        fputc(ch, ppout);
574
                                waitpid(zpp_pid, &zpp_status, WNOHANG);
575 16 dgisselq
                        } else {
576 26 dgisselq
                                yyrestart(run_preprocessor(zpp_pid, path_to_zasm, master_input_filename));
577 16 dgisselq
                                yylineno = 1;
578
                                yyparse();
579 26 dgisselq
                                waitpid(zpp_pid, &zpp_status, WNOHANG);
580 16 dgisselq
                        }
581 13 dgisselq
                }
582
        } else { // Run from Stdin
583
                extern  FILE    *yyin;
584
                extern  void    yyrestart(FILE *);
585
 
586
                create_new_context();
587
                master_input_filename = strdup("(stdin)");
588 16 dgisselq
                if (preprocess_only) {
589
                        int     ch;
590 26 dgisselq
                                FILE    *fp = run_preprocessor(zpp_pid, path_to_zasm, master_input_filename);
591 16 dgisselq
                        while(EOF != (ch = fgetc(fp)))
592 26 dgisselq
                                fputc(ch, ppout);
593
                        waitpid(zpp_pid, &zpp_status, WNOHANG);
594 16 dgisselq
                } else {
595 26 dgisselq
                        yyin = run_preprocessor(zpp_pid, NULL);
596 16 dgisselq
                        yyrestart(yyin);
597
                        yyparse();
598 26 dgisselq
                        waitpid(zpp_pid, &zpp_status, WNOHANG);
599 16 dgisselq
                }
600 13 dgisselq
        }
601
 
602 26 dgisselq
        if (0 != WEXITSTATUS(zpp_status)) {
603
                if (!preprocess_only) {
604
                        objcode.close();
605
                        unlink(zout_fname);
606
                }
607
        } if (!objcode.reduce())
608 13 dgisselq
                fprintf(stderr, "Not all symbols defined!\n");
609
}
610
 
611
 

powered by: WebSVN 2.1.0

© copyright 1999-2022 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.