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

Subversion Repositories zipcpu

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

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

powered by: WebSVN 2.1.0

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