/*******************************************************************************
|
/*******************************************************************************
|
**
|
**
|
** Filename: zasm.y
|
** Filename: zasm.y
|
**
|
**
|
** Project: Zip CPU -- a small, lightweight, RISC CPU core
|
** Project: Zip CPU -- a small, lightweight, RISC CPU core
|
**
|
**
|
** Purpose: The parser for the Zip Assembler. This is actually not just
|
** Purpose: The parser for the Zip Assembler. This is actually not just
|
** the parser, but the main program as well.
|
** the parser, but the main program as well.
|
**
|
**
|
** Creator: Dan Gisselquist, Ph.D.
|
** Creator: Dan Gisselquist, Ph.D.
|
** Gisselquist Tecnology, LLC
|
** Gisselquist Tecnology, LLC
|
**
|
**
|
********************************************************************************
|
********************************************************************************
|
**
|
**
|
** Copyright (C) 2015, Gisselquist Technology, LLC
|
** Copyright (C) 2015, Gisselquist Technology, LLC
|
**
|
**
|
** This program is free software (firmware): you can redistribute it and/or
|
** This program is free software (firmware): you can redistribute it and/or
|
** modify it under the terms of the GNU General Public License as published
|
** modify it under the terms of the GNU General Public License as published
|
** by the Free Software Foundation, either version 3 of the License, or (at
|
** by the Free Software Foundation, either version 3 of the License, or (at
|
** your option) any later version.
|
** your option) any later version.
|
**
|
**
|
** This program is distributed in the hope that it will be useful, but WITHOUT
|
** This program is distributed in the hope that it will be useful, but WITHOUT
|
** ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
** ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
** for more details.
|
** for more details.
|
**
|
**
|
** You should have received a copy of the GNU General Public License along
|
** You should have received a copy of the GNU General Public License along
|
** with this program. (It's in the $(ROOT)/doc directory, run make with no
|
** with this program. (It's in the $(ROOT)/doc directory, run make with no
|
** target there if the PDF file isn't present.) If not, see
|
** target there if the PDF file isn't present.) If not, see
|
** for a copy.
|
** for a copy.
|
**
|
**
|
** License: GPL, v3, as defined and found on www.gnu.org,
|
** License: GPL, v3, as defined and found on www.gnu.org,
|
** http://www.gnu.org/licenses/gpl.html
|
** http://www.gnu.org/licenses/gpl.html
|
**
|
**
|
**
|
**
|
*******************************************************************************/
|
*******************************************************************************/
|
|
|
%{
|
%{
|
#include
|
#include
|
|
#include
|
#include
|
#include
|
#include "asmdata.h"
|
#include "asmdata.h"
|
|
|
#define DEFAULT_OUTPUT_FNAME "z.out"
|
#define DEFAULT_OUTPUT_FNAME "z.out"
|
#define YYDEBUG 1
|
#define YYDEBUG 1
|
|
|
extern "C" int yylex(void);
|
extern "C" int yylex(void);
|
extern "C" int yyparse(void);
|
extern "C" int yyparse(void);
|
// extern "C" FILE *yyin;
|
// extern "C" FILE *yyin;
|
void yyerror(const char *);
|
void yyerror(const char *);
|
unsigned int global_parser_pc;
|
unsigned int global_parser_pc;
|
char *master_input_filename = NULL;
|
char *master_input_filename = NULL;
|
extern int yylineno;
|
extern int yylineno;
|
char *linecp = NULL; // A copy of the input line
|
char *linecp = NULL; // A copy of the input line
|
%}
|
%}
|
|
|
%token COMMA EQU PLUS MINUS TIMES HERE DOLLAR COLON
|
%token COMMA EQU PLUS MINUS TIMES HERE DOLLAR COLON
|
%token BOOLEANOR BITWISEOR BOOLEANAND BITWISEAND BITWISEXOR DOT
|
%token BOOLEANOR BITWISEOR BOOLEANAND BITWISEAND BITWISEXOR DOT
|
%token WORD FILL
|
%token WORD FILL
|
%token LOADOP STOROP LDIOP
|
%token LOADOP STOROP LDIOP
|
%token BAREOP BRANCHOP COND DUALOP IDENTIFIER INT LDHLOP REG SINGLOP
|
%token BAREOP BRANCHOP COND DUALOP IDENTIFIER INT LDHLOP REG SINGLOP
|
|
|
%union {
|
%union {
|
ZPARSER::ZIPREG u_reg;
|
ZPARSER::ZIPREG u_reg;
|
ZPARSER::ZIPCOND u_cond;
|
ZPARSER::ZIPCOND u_cond;
|
int u_ival;
|
int u_ival;
|
LEXOPCODE u_op;
|
LEXOPCODE u_op;
|
char *u_id;
|
char *u_id;
|
ASMLINE *u_ln;
|
ASMLINE *u_ln;
|
AST *u_ast;
|
AST *u_ast;
|
}
|
}
|
|
|
%type REG
|
%type REG
|
%type COND opcond
|
%type COND opcond
|
%type INT
|
%type INT
|
%type IDENTIFIER
|
%type IDENTIFIER
|
%type BAREOP SINGLOP DUALOP BRANCHOP LDHLOP
|
%type BAREOP SINGLOP DUALOP BRANCHOP LDHLOP
|
%type unlabeledline instruction wordlist fillist opb
|
%type unlabeledline instruction wordlist fillist opb
|
%type bareop singlop dualop loadop storop line
|
%type bareop singlop dualop loadop storop line
|
%type expr value multident
|
%type expr value multident
|
|
|
%left BOOLEANOR
|
%left BOOLEANOR
|
%left BOOLEANAND
|
%left BOOLEANAND
|
%left BITWISEOR BITWISEXOR
|
%left BITWISEOR BITWISEXOR
|
%left BITWISEAND
|
%left BITWISEAND
|
%left '%'
|
%left '%'
|
%left PLUS MINUS
|
%left PLUS MINUS
|
%left TIMES '/'
|
%left TIMES '/'
|
|
|
%% /* The grammar follows */
|
%% /* The grammar follows */
|
|
|
input:
|
input:
|
%empty
|
%empty
|
| input line { if ($2) {objcode += $2; global_parser_pc += $2->nlines(); if ($2->isdefined()) delete $2; } }
|
| input line { if ($2) {objcode += $2; global_parser_pc += $2->nlines(); if ($2->isdefined()) delete $2; } }
|
;
|
;
|
|
|
line:
|
line:
|
'\n' { $$ = NULL; }
|
'\n' { $$ = NULL; }
|
| unlabeledline '\n' { $$ = $1; }
|
| unlabeledline '\n' { $$ = $1; }
|
| multident COLON unlabeledline '\n' {
|
| multident COLON unlabeledline '\n' {
|
if ($1->m_node_type == 'I') {
|
if ($1->m_node_type == 'I') {
|
if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
|
if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
|
stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
else
|
else
|
gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
delete $1;
|
delete $1;
|
}
|
}
|
$$ = $3;
|
$$ = $3;
|
}
|
}
|
| multident COLON '\n' {
|
| multident COLON '\n' {
|
if ($1->m_node_type == 'I') {
|
if ($1->m_node_type == 'I') {
|
if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
|
if (((AST_IDENTIFIER*)$1)->m_id[0] == 'L')
|
stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
stb_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
else
|
else
|
gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
gbl_define(((AST_IDENTIFIER *)$1)->m_id, new AST_NUMBER(global_parser_pc));
|
delete $1;
|
delete $1;
|
}
|
}
|
$$ = new VLINE();
|
$$ = new VLINE();
|
}
|
}
|
| multident EQU expr '\n' {
|
| multident EQU expr '\n' {
|
if ($1->m_node_type == 'I') {
|
if ($1->m_node_type == 'I') {
|
stb_define(((AST_IDENTIFIER *)$1)->m_id, $3);
|
stb_define(((AST_IDENTIFIER *)$1)->m_id, $3);
|
delete $1;
|
delete $1;
|
}
|
}
|
$$ = new VLINE();
|
$$ = new VLINE();
|
}
|
}
|
;
|
;
|
|
|
unlabeledline:
|
unlabeledline:
|
instruction { $$ = $1; }
|
instruction { $$ = $1; }
|
| WORD wordlist { $$ = $2; }
|
| WORD wordlist { $$ = $2; }
|
| FILL fillist { $$ = $2; }
|
| FILL fillist { $$ = $2; }
|
;
|
;
|
|
|
wordlist:
|
wordlist:
|
expr {
|
expr {
|
if ($1->isdefined())
|
if ($1->isdefined())
|
$$ = new DLINE($1->eval());
|
$$ = new DLINE($1->eval());
|
else {
|
else {
|
$$ = new VLINE();
|
$$ = new VLINE();
|
yyerror("ERROR: word list undefined");
|
yyerror("ERROR: word list undefined");
|
}}
|
}}
|
| wordlist COMMA expr {
|
| wordlist COMMA expr {
|
if ($3->isdefined()) {
|
if ($3->isdefined()) {
|
LLINE *ln;
|
LLINE *ln;
|
if ($1->m_state == 'L') {
|
if ($1->m_state == 'L') {
|
ln = ((LLINE *)$1);
|
ln = ((LLINE *)$1);
|
} else {
|
} else {
|
ln = new LLINE();
|
ln = new LLINE();
|
ln->addline($1);
|
ln->addline($1);
|
} ln->addline(new DLINE($3->eval()));
|
} ln->addline(new DLINE($3->eval()));
|
$$ = ln;
|
$$ = ln;
|
} else {
|
} else {
|
$$ = new VLINE();
|
$$ = new VLINE();
|
yyerror("ERROR: word list undefined\n");
|
yyerror("ERROR: word list undefined\n");
|
}}
|
}}
|
;
|
;
|
|
|
fillist:
|
fillist:
|
expr COMMA expr {
|
expr COMMA expr {
|
if (($1->isdefined())&&($3->isdefined())) {
|
if (($1->isdefined())&&($3->isdefined())) {
|
int ntimes = $1->eval(),
|
int ntimes = $1->eval(),
|
val = $3->eval();
|
val = $3->eval();
|
LLINE *ln = new LLINE();
|
LLINE *ln = new LLINE();
|
for(int i=0; i
|
for(int i=0; i
|
ln->addline(new DLINE(val));
|
ln->addline(new DLINE(val));
|
$$ = ln;
|
$$ = ln;
|
} else {
|
} else {
|
yyerror("Fill list undefined\n");
|
yyerror("Fill list undefined\n");
|
$$ = new VLINE();
|
$$ = new VLINE();
|
}
|
}
|
}
|
}
|
;
|
;
|
|
|
instruction:
|
instruction:
|
dualop opb COMMA REG {
|
dualop opb COMMA REG {
|
$$ = $1;
|
$$ = $1;
|
((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
|
((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
|
((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
|
((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
|
((TLINE*)$1)->m_opa = $4;
|
((TLINE*)$1)->m_opa = $4;
|
if ($1->isdefined()) {
|
if ($1->isdefined()) {
|
$$ = ((TLINE*)$1)->eval();
|
$$ = ((TLINE*)$1)->eval();
|
delete $1;
|
delete $1;
|
delete $2;
|
delete $2;
|
}
|
}
|
}
|
}
|
| dualop opb COMMA multident {
|
| dualop opb COMMA multident {
|
char buf[256];
|
char buf[256];
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
|
yyerror(buf);
|
yyerror(buf);
|
$$ = new VLINE();
|
$$ = new VLINE();
|
delete $1;
|
delete $1;
|
delete $2;
|
delete $2;
|
delete $4;
|
delete $4;
|
}
|
}
|
| singlop opb {
|
| singlop opb {
|
$$ = $1;
|
$$ = $1;
|
((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
|
((TLINE*)$1)->m_imm = ((TLINE*)$2)->m_imm; ((TLINE*)$2)->m_imm = NULL;
|
((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
|
((TLINE*)$1)->m_opb = ((TLINE*)$2)->m_opb;
|
if ($1->isdefined()) {
|
if ($1->isdefined()) {
|
$$ = ((TLINE *)$1)->eval();
|
$$ = ((TLINE *)$1)->eval();
|
delete $1;
|
delete $1;
|
}
|
}
|
}
|
}
|
| bareop { $$ = $1; }
|
| bareop { $$ = $1; }
|
| LDHLOP opcond expr COMMA REG {
|
| LDHLOP opcond expr COMMA REG {
|
TLINE *tln = new TLINE;
|
TLINE *tln = new TLINE;
|
tln->m_opcode = $1;
|
tln->m_opcode = $1;
|
tln->m_cond = $2;
|
tln->m_cond = $2;
|
tln->m_imm = $3;
|
tln->m_imm = $3;
|
tln->m_opa = $5;
|
tln->m_opa = $5;
|
|
|
if (tln->isdefined()) {
|
if (tln->isdefined()) {
|
$$ = tln->eval();
|
$$ = tln->eval();
|
delete tln;
|
delete tln;
|
} else
|
} else
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| LDHLOP opcond expr COMMA multident {
|
| LDHLOP opcond expr COMMA multident {
|
char buf[256];
|
char buf[256];
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$5)->m_id.c_str());
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$5)->m_id.c_str());
|
yyerror(buf);
|
yyerror(buf);
|
$$ = new VLINE();
|
$$ = new VLINE();
|
delete $3;
|
delete $3;
|
delete $5;
|
delete $5;
|
}
|
}
|
| LDIOP expr COMMA REG {
|
| LDIOP expr COMMA REG {
|
TLINE *tln = new TLINE;
|
TLINE *tln = new TLINE;
|
tln->m_opcode = OP_LDI;
|
tln->m_opcode = OP_LDI;
|
tln->m_cond = ZPARSER::ZIPC_ALWAYS;
|
tln->m_cond = ZPARSER::ZIPC_ALWAYS;
|
tln->m_imm = $2;
|
tln->m_imm = $2;
|
tln->m_opa = $4;
|
tln->m_opa = $4;
|
|
|
if (tln->isdefined()) {
|
if (tln->isdefined()) {
|
$$ = tln->eval();
|
$$ = tln->eval();
|
delete tln;
|
delete tln;
|
} else
|
} else
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| LDIOP expr COMMA multident {
|
| LDIOP expr COMMA multident {
|
char buf[256];
|
char buf[256];
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
|
yyerror(buf);
|
yyerror(buf);
|
$$ = new VLINE();
|
$$ = new VLINE();
|
delete $2;
|
delete $2;
|
delete $4;
|
delete $4;
|
}
|
}
|
| BRANCHOP expr {
|
| BRANCHOP expr {
|
TLINE *tln = new TLINE;
|
TLINE *tln = new TLINE;
|
tln->m_opcode = $1;
|
tln->m_opcode = $1;
|
tln->m_imm = $2;
|
tln->m_imm = $2;
|
|
|
if (tln->isdefined()) {
|
if (tln->isdefined()) {
|
$$ = tln->eval();
|
$$ = tln->eval();
|
delete tln;
|
delete tln;
|
} else
|
} else
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| loadop opb COMMA REG {
|
| loadop opb COMMA REG {
|
TLINE *tln = new TLINE;
|
TLINE *tln = new TLINE;
|
((TLINE*)$2)->m_opcode = OP_LOD;
|
((TLINE*)$2)->m_opcode = OP_LOD;
|
((TLINE*)$2)->m_cond = ((TLINE*)$1)->m_cond;
|
((TLINE*)$2)->m_cond = ((TLINE*)$1)->m_cond;
|
((TLINE*)$2)->m_opa = $4;
|
((TLINE*)$2)->m_opa = $4;
|
|
|
delete $1;
|
delete $1;
|
|
|
if (((TLINE *)$2)->isdefined()) {
|
if (((TLINE *)$2)->isdefined()) {
|
$$ = ((TLINE *)$2)->eval();
|
$$ = ((TLINE *)$2)->eval();
|
delete $2;
|
delete $2;
|
} else
|
} else
|
$$ = $2;
|
$$ = $2;
|
}
|
}
|
| loadop opb COMMA multident {
|
| loadop opb COMMA multident {
|
char buf[256];
|
char buf[256];
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$4)->m_id.c_str());
|
yyerror(buf);
|
yyerror(buf);
|
$$ = new VLINE();
|
$$ = new VLINE();
|
delete $1;
|
delete $1;
|
delete $2;
|
delete $2;
|
delete $4;
|
delete $4;
|
}
|
}
|
| storop REG COMMA opb {
|
| storop REG COMMA opb {
|
TLINE *tln = new TLINE;
|
TLINE *tln = new TLINE;
|
tln->m_opcode = OP_STO;
|
tln->m_opcode = OP_STO;
|
tln->m_cond = ((TLINE*)$1)->m_cond;
|
tln->m_cond = ((TLINE*)$1)->m_cond;
|
tln->m_imm = ((TLINE*)$4)->m_imm;
|
tln->m_imm = ((TLINE*)$4)->m_imm;
|
tln->m_opb = ((TLINE*)$4)->m_opb;
|
tln->m_opb = ((TLINE*)$4)->m_opb;
|
tln->m_opa = $2;
|
tln->m_opa = $2;
|
|
|
delete $1;
|
delete $1;
|
|
|
if (tln->isdefined()) {
|
if (tln->isdefined()) {
|
$$ = tln->eval();
|
$$ = tln->eval();
|
delete tln;
|
delete tln;
|
} else
|
} else
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| storop multident COMMA opb {
|
| storop multident COMMA opb {
|
char buf[256];
|
char buf[256];
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$2)->m_id.c_str());
|
sprintf(buf, "%s is not a register", ((AST_IDENTIFIER *)$2)->m_id.c_str());
|
yyerror(buf);
|
yyerror(buf);
|
$$ = new VLINE();
|
$$ = new VLINE();
|
delete $1;
|
delete $1;
|
delete $2;
|
delete $2;
|
delete $4;
|
delete $4;
|
}
|
}
|
;
|
;
|
|
|
dualop: DUALOP opcond {
|
dualop: DUALOP opcond {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_opcode = $1;
|
tln->m_opcode = $1;
|
tln->m_cond = $2;
|
tln->m_cond = $2;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
;
|
;
|
|
|
singlop: SINGLOP opcond {
|
singlop: SINGLOP opcond {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_opcode = $1;
|
tln->m_opcode = $1;
|
tln->m_cond = $2;
|
tln->m_cond = $2;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
;
|
;
|
|
|
storop: STOROP opcond {
|
storop: STOROP opcond {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_opcode = OP_STO;
|
tln->m_opcode = OP_STO;
|
tln->m_cond = $2;
|
tln->m_cond = $2;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
;
|
;
|
|
|
loadop: LOADOP opcond {
|
loadop: LOADOP opcond {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_opcode = OP_LOD;
|
tln->m_opcode = OP_LOD;
|
tln->m_cond = $2;
|
tln->m_cond = $2;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
;
|
;
|
|
|
bareop: BAREOP opcond {
|
bareop: BAREOP opcond {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_opcode = $1;
|
tln->m_opcode = $1;
|
tln->m_cond = $2;
|
tln->m_cond = $2;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
;
|
;
|
|
|
opcond:
|
opcond:
|
COND { $$ = $1; }
|
COND { $$ = $1; }
|
| %empty { $$ = ZPARSER::ZIPC_ALWAYS; }
|
| %empty { $$ = ZPARSER::ZIPC_ALWAYS; }
|
;
|
;
|
|
|
opb:
|
opb:
|
expr {
|
expr {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_imm = $1;
|
tln->m_imm = $1;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| expr PLUS REG {
|
| expr PLUS REG {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_imm = $1;
|
tln->m_imm = $1;
|
tln->m_opb = $3;
|
tln->m_opb = $3;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| expr '(' REG ')' {
|
| expr '(' REG ')' {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_imm = $1;
|
tln->m_imm = $1;
|
tln->m_opb = $3;
|
tln->m_opb = $3;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| '(' REG ')' {
|
| '(' REG ')' {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_imm = new AST_NUMBER(0);
|
tln->m_imm = new AST_NUMBER(0);
|
tln->m_opb = $2;
|
tln->m_opb = $2;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
| REG {
|
| REG {
|
TLINE *tln = new TLINE();
|
TLINE *tln = new TLINE();
|
tln->m_imm = new AST_NUMBER(0);
|
tln->m_imm = new AST_NUMBER(0);
|
tln->m_opb = $1;
|
tln->m_opb = $1;
|
$$ = tln;
|
$$ = tln;
|
}
|
}
|
;
|
;
|
|
|
expr:
|
expr:
|
value { $$ = $1; }
|
value { $$ = $1; }
|
| MINUS value %prec TIMES { $$ = new AST_BRANCH('-',new AST_NUMBER(0), $2); }
|
| MINUS value %prec TIMES { $$ = new AST_BRANCH('-',new AST_NUMBER(0), $2); }
|
| expr PLUS expr { $$ = new AST_BRANCH('+',$1,$3); }
|
| expr PLUS expr { $$ = new AST_BRANCH('+',$1,$3); }
|
| expr MINUS expr { $$ = new AST_BRANCH('-',$1,$3); }
|
| expr MINUS expr { $$ = new AST_BRANCH('-',$1,$3); }
|
| expr TIMES expr { $$ = new AST_BRANCH('*',$1,$3); }
|
| expr TIMES expr { $$ = new AST_BRANCH('*',$1,$3); }
|
| expr '/' expr { $$ = new AST_BRANCH('/',$1,$3); }
|
| expr '/' expr { $$ = new AST_BRANCH('/',$1,$3); }
|
| expr '%' expr { $$ = new AST_BRANCH('%',$1,$3); }
|
| expr '%' expr { $$ = new AST_BRANCH('%',$1,$3); }
|
| expr BOOLEANOR expr { $$ = new AST_BRANCH('o',$1,$3); }
|
| expr BOOLEANOR expr { $$ = new AST_BRANCH('o',$1,$3); }
|
| expr BITWISEOR expr { $$ = new AST_BRANCH('|',$1,$3); }
|
| expr BITWISEOR expr { $$ = new AST_BRANCH('|',$1,$3); }
|
| expr BOOLEANAND expr { $$ = new AST_BRANCH('a',$1,$3); }
|
| expr BOOLEANAND expr { $$ = new AST_BRANCH('a',$1,$3); }
|
| expr BITWISEAND expr { $$ = new AST_BRANCH('&',$1,$3); }
|
| expr BITWISEAND expr { $$ = new AST_BRANCH('&',$1,$3); }
|
| expr BITWISEXOR expr { $$ = new AST_BRANCH('^',$1,$3); }
|
| expr BITWISEXOR expr { $$ = new AST_BRANCH('^',$1,$3); }
|
| '(' expr ')' { $$ = $2; }
|
| '(' expr ')' { $$ = $2; }
|
;
|
;
|
/* expr OR (|) value */
|
/* expr OR (|) value */
|
/* expr XOR (^) value */
|
/* expr XOR (^) value */
|
/* expr AND (&) value */
|
/* expr AND (&) value */
|
|
|
value:
|
value:
|
INT { $$ = new AST_NUMBER($1); }
|
INT { $$ = new AST_NUMBER($1); }
|
| multident { $$ = $1; }
|
| multident { $$ = $1; }
|
| HERE { $$ = new AST_NUMBER(global_parser_pc); }
|
| HERE { $$ = new AST_NUMBER(global_parser_pc); }
|
;
|
;
|
|
|
multident:
|
multident:
|
IDENTIFIER { $$ = new AST_IDENTIFIER($1); delete $1; }
|
IDENTIFIER { $$ = new AST_IDENTIFIER($1); delete $1; }
|
| multident DOT IDENTIFIER { $$ = new AST_IDENTIFIER($1,$3); delete $3; }
|
| multident DOT IDENTIFIER { $$ = new AST_IDENTIFIER($1,$3); delete $3; }
|
;
|
;
|
%%
|
%%
|
|
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
|
#include
|
|
|
OBJFILE objcode;
|
OBJFILE objcode;
|
|
|
void yyerror(const char *str) {
|
void yyerror(const char *str) {
|
fprintf(stderr, "%s:%d: ERROR: %s\n", master_input_filename, yylineno, str);
|
fprintf(stderr, "%s:%d: ERROR: %s\n", master_input_filename, yylineno, str);
|
if (linecp) fprintf(stderr, "Offending line was: %s\n", linecp);
|
if (linecp) fprintf(stderr, "Offending line was: %s\n", linecp);
|
}
|
}
|
|
|
FILE *run_preprocessor(pid_t &pid, const char *path = NULL, const char *zname = NULL) {
|
FILE *run_preprocessor(pid_t &pid, const char *path = NULL, const char *zname = NULL) {
|
int pipefd[2];
|
int pipefd[2];
|
|
|
if (pipe(pipefd)!=0) {
|
if (pipe(pipefd)!=0) {
|
fprintf(stderr, "PIPE FAILED!\n");
|
fprintf(stderr, "PIPE FAILED!\n");
|
perror("O/S Err:");
|
perror("O/S Err:");
|
exit(-2);
|
exit(-2);
|
} if ((zname)&&(access(zname, R_OK)!=0)) { // if !zname, then use stdin
|
} if ((zname)&&(access(zname, R_OK)!=0)) { // if !zname, then use stdin
|
fprintf(stderr, "Cannot open %s\n", zname);
|
fprintf(stderr, "Cannot open %s\n", zname);
|
perror("O/S Err:");
|
perror("O/S Err:");
|
exit(-2);
|
exit(-2);
|
}
|
}
|
|
|
|
|
if (0 == (pid = fork())) {
|
if (0 == (pid = fork())) {
|
int fdin, fdout;
|
int fdin, fdout;
|
|
|
// Child process -- run the preprocessor
|
// Child process -- run the preprocessor
|
|
|
// Close the reader: we write only
|
// Close the reader: we write only
|
close(pipefd[0]);
|
close(pipefd[0]);
|
|
|
// Adjust stdout to write to our pipe instead of anywhere else
|
// Adjust stdout to write to our pipe instead of anywhere else
|
fdout = pipefd[1];
|
fdout = pipefd[1];
|
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
dup2(fdout, STDOUT_FILENO);
|
dup2(fdout, STDOUT_FILENO);
|
|
|
char *zpp_path;
|
char *zpp_path;
|
if (path != NULL) {
|
if (path != NULL) {
|
zpp_path = new char[strlen(path+1+strlen("/zpp"))];
|
zpp_path = new char[strlen(path+1+strlen("/zpp"))];
|
strcpy(zpp_path, path);
|
strcpy(zpp_path, path);
|
strcat(zpp_path, "/zpp");
|
strcat(zpp_path, "/zpp");
|
} else zpp_path = strdup("zpp");
|
} else zpp_path = strdup("zpp");
|
|
|
// This call should never return
|
// This call should never return
|
// We have to pass the name here, rather than an open file,
|
// We have to pass the name here, rather than an open file,
|
// since zpp needs to mark for us what file it is in at all
|
// since zpp needs to mark for us what file it is in at all
|
// times.
|
// times.
|
if (zname)
|
if (zname)
|
execlp(zpp_path, "zpp", zname, NULL);
|
execlp(zpp_path, "zpp", zname, NULL);
|
else
|
else
|
execlp(zpp_path, "zpp", NULL);
|
execlp(zpp_path, "zpp", NULL);
|
|
|
fprintf(stderr, "Could not start pre-processor!\n");
|
fprintf(stderr, "Could not start pre-processor!\n");
|
perror("O/S Err:");
|
perror("O/S Err:");
|
|
|
exit(-5);
|
exit(-5);
|
}
|
}
|
|
|
close(pipefd[1]);
|
close(pipefd[1]);
|
return fdopen(pipefd[0], "r");
|
return fdopen(pipefd[0], "r");
|
}
|
}
|
|
|
void usage(void) {
|
void usage(void) {
|
printf("USAGE: zasm [-h] [-d] [-E] [-o ] [ ]* ...\n");
|
printf("USAGE: zasm [-h] [-d] [-E] [-o ] [ ]* ...\n");
|
printf("\t-d\tTurns on debugging in the parser\n");
|
printf("\t-d\tTurns on debugging in the parser\n");
|
printf("\t-E\tProduces preprocessor output only\n");
|
printf("\t-E\tProduces preprocessor output only\n");
|
printf("\t-h\tDisplays this message\n");
|
printf("\t-h\tDisplays this message\n");
|
printf("\t-o \tWrites the output to . The\n"
|
printf("\t-o \tWrites the output to . The\n"
|
"\t\tdefault output file is \"" DEFAULT_OUTPUT_FNAME "\".\n");
|
"\t\tdefault output file is \"" DEFAULT_OUTPUT_FNAME "\".\n");
|
|
|
printf("\t-I \tSearch for include files.\n");
|
printf("\t-I \tSearch for include files.\n");
|
}
|
}
|
|
|
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
int skp = 0;
|
int skp = 0;
|
const char *zout_fname = NULL;
|
const char *zout_fname = NULL;
|
char *path_to_zasm = NULL;
|
char *path_to_zasm = NULL;
|
bool preprocess_only = false;
|
bool preprocess_only = false;
|
FILE *ppout;
|
FILE *ppout;
|
pid_t zpp_pid;
|
pid_t zpp_pid;
|
int zpp_status;
|
int zpp_status;
|
|
std::string inclist;
|
|
if (NULL != getenv("ZIPINC"))
|
|
inclist = getenv("ZIPINC");
|
|
|
|
printf("Original INCLIST = %s\n", inclist.c_str());
|
|
|
master_input_filename = NULL;
|
master_input_filename = NULL;
|
|
|
// Find what directory zasm is in, so that we can find zpp when
|
// Find what directory zasm is in, so that we can find zpp when
|
// necessary.
|
// necessary.
|
path_to_zasm = NULL;
|
path_to_zasm = NULL;
|
if (strchr(argv[0], '/')) {
|
if (strchr(argv[0], '/')) {
|
path_to_zasm = strdup(argv[0]);
|
path_to_zasm = strdup(argv[0]);
|
char *ptr = strrchr(path_to_zasm,'/');
|
char *ptr = strrchr(path_to_zasm,'/');
|
*ptr = '\0';
|
*ptr = '\0';
|
}
|
}
|
|
|
skp=1;
|
skp=1;
|
for(int argn=0; argn+skp
|
for(int argn=0; argn+skp
|
if (argv[argn+skp][0] == '-') {
|
if (argv[argn+skp][0] == '-') {
|
if (argv[argn+skp][1] == 'o') {
|
if (argv[argn+skp][1] == 'o') {
|
if (zout_fname)
|
if (zout_fname)
|
free((void *)zout_fname);
|
free((void *)zout_fname);
|
zout_fname = strdup(argv[argn+skp+1]);
|
zout_fname = strdup(argv[argn+skp+1]);
|
skp++;
|
skp++;
|
} else if (argv[argn+skp][1] == 'E')
|
} else if (argv[argn+skp][1] == 'E')
|
preprocess_only = true;
|
preprocess_only = true;
|
else if (argv[argn+skp][1] == 'd')
|
else if (argv[argn+skp][1] == 'I') {
|
|
if (argv[argn+skp][2]) {
|
|
if (inclist.size() != 0) {
|
|
inclist += std::string(":");
|
|
inclist += &argv[argn+skp][2];
|
|
} else
|
|
inclist = &argv[argn+skp][2];
|
|
} else if (argn+skp+1
|
|
if (inclist.size() != 0) {
|
|
inclist += std::string(":");
|
|
inclist += &argv[argn+skp+1][2];
|
|
} else
|
|
inclist = &argv[argn+skp+1][2];
|
|
argn++;
|
|
}
|
|
} else if (argv[argn+skp][1] == 'd')
|
yydebug = 1;
|
yydebug = 1;
|
else if (argv[argn+skp][1] == 'h') {
|
else if (argv[argn+skp][1] == 'h') {
|
usage();
|
usage();
|
exit(0);
|
exit(0);
|
}
|
}
|
|
|
skp++;
|
skp++;
|
} argv[argn] = argv[argn+skp];
|
} argv[argn] = argv[argn+skp];
|
} argc -= skp;
|
} argc -= skp;
|
|
|
if (zout_fname) {
|
if (zout_fname) {
|
for(int argn=0; argn
|
for(int argn=0; argn
|
if (strcmp(zout_fname, argv[argn])==0) {
|
if (strcmp(zout_fname, argv[argn])==0) {
|
fprintf(stderr, "ERR: Cowardly refusing to overwrite \'%s\'\n", zout_fname);
|
fprintf(stderr, "ERR: Cowardly refusing to overwrite \'%s\'\n", zout_fname);
|
exit(-2);
|
exit(-2);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
printf("New INCLIST = %s\n", inclist.c_str());
|
|
|
if (preprocess_only) {
|
if (preprocess_only) {
|
objcode.open("/dev/null");
|
objcode.open("/dev/null");
|
if (zout_fname)
|
if (zout_fname)
|
ppout = fopen(zout_fname, "w");
|
ppout = fopen(zout_fname, "w");
|
else
|
else
|
ppout = stdout;
|
ppout = stdout;
|
} else {
|
} else {
|
if (!zout_fname)
|
if (!zout_fname)
|
zout_fname = DEFAULT_OUTPUT_FNAME;
|
zout_fname = DEFAULT_OUTPUT_FNAME;
|
|
|
objcode.open(zout_fname);
|
objcode.open(zout_fname);
|
}
|
}
|
|
|
|
setenv("ZIPINC",inclist.c_str(), 1);
|
master_input_filename = NULL;
|
master_input_filename = NULL;
|
|
|
if (argc > 0) {
|
if (argc > 0) {
|
for(int argn=0; argn
|
for(int argn=0; argn
|
extern FILE *yyin;
|
extern FILE *yyin;
|
extern void yyrestart(FILE *);
|
extern void yyrestart(FILE *);
|
FILE *tst;
|
FILE *tst;
|
|
|
create_new_context();
|
create_new_context();
|
if (master_input_filename)
|
if (master_input_filename)
|
free(master_input_filename);
|
free(master_input_filename);
|
master_input_filename = strdup(argv[argn]);
|
master_input_filename = strdup(argv[argn]);
|
if (preprocess_only) {
|
if (preprocess_only) {
|
FILE *fp = run_preprocessor(zpp_pid, path_to_zasm, master_input_filename);
|
FILE *fp = run_preprocessor(zpp_pid, path_to_zasm, master_input_filename);
|
int ch;
|
int ch;
|
while(EOF != (ch = fgetc(fp)))
|
while(EOF != (ch = fgetc(fp)))
|
fputc(ch, ppout);
|
fputc(ch, ppout);
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
} else {
|
} else {
|
yyrestart(run_preprocessor(zpp_pid, path_to_zasm, master_input_filename));
|
yyrestart(run_preprocessor(zpp_pid, path_to_zasm, master_input_filename));
|
yylineno = 1;
|
yylineno = 1;
|
yyparse();
|
yyparse();
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
}
|
}
|
}
|
}
|
} else { // Run from Stdin
|
} else { // Run from Stdin
|
extern FILE *yyin;
|
extern FILE *yyin;
|
extern void yyrestart(FILE *);
|
extern void yyrestart(FILE *);
|
|
|
create_new_context();
|
create_new_context();
|
master_input_filename = strdup("(stdin)");
|
master_input_filename = strdup("(stdin)");
|
if (preprocess_only) {
|
if (preprocess_only) {
|
int ch;
|
int ch;
|
FILE *fp = run_preprocessor(zpp_pid, path_to_zasm, master_input_filename);
|
FILE *fp = run_preprocessor(zpp_pid, path_to_zasm, master_input_filename);
|
while(EOF != (ch = fgetc(fp)))
|
while(EOF != (ch = fgetc(fp)))
|
fputc(ch, ppout);
|
fputc(ch, ppout);
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
} else {
|
} else {
|
yyin = run_preprocessor(zpp_pid, NULL);
|
yyin = run_preprocessor(zpp_pid, NULL);
|
yyrestart(yyin);
|
yyrestart(yyin);
|
yyparse();
|
yyparse();
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
waitpid(zpp_pid, &zpp_status, WNOHANG);
|
}
|
}
|
}
|
}
|
|
|
if (0 != WEXITSTATUS(zpp_status)) {
|
if (0 != WEXITSTATUS(zpp_status)) {
|
if (!preprocess_only) {
|
if (!preprocess_only) {
|
objcode.close();
|
objcode.close();
|
unlink(zout_fname);
|
unlink(zout_fname);
|
}
|
}
|
} if (!objcode.reduce())
|
} if (!objcode.reduce())
|
fprintf(stderr, "Not all symbols defined!\n");
|
fprintf(stderr, "Not all symbols defined!\n");
|
}
|
}
|
|
|
|
|
|
|