%{ /* * Copyright (c) 1991 Paul Campbell * All Rights Reserved * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF Paul Campbell * The copyright notice above does not evidence any * actual or intended publication of such source code. */ #include #include #include "lex.h" #pragma segment parser extern int op_size, pass, valid, text, data; int dswap; extern unsigned short pc; extern unsigned short text_pc; extern unsigned short data_pc; extern void emit1(); extern void emit2(); extern void emit3(); #define P1(x) op_size = (x);if (pass == 1) break; static char *cp; static int csize; extern long yyline; extern int brflg; unsigned char chrel(long offset) { if (pass == 2 && (offset < -128 || offset > 127)) yyerror("Short branch target out of range",0,0,0,0,0,0); return(offset&0xff); } unsigned char cha(long offset, long type, long inc) { if (pass == 2 && (offset&0xf800) != ((pc+inc)&0xf800)) if (brflg) { if (type) { fprintf(stderr, "if ($line == %d) {$a =~ s/acall/lcall/;};\n",yyline); } else { fprintf(stderr, "if ($line == %d) {$a =~ s/ajmp/ljmp/;};\n",yyline); } } else { yyerror("Branch target out of range",0,0,0,0,0,0); } return(offset); } unsigned char chl(long offset, long type, long inc) { if (pass == 2 && (offset&0xf800) == ((pc+inc)&0xf800) && brflg) { if (type) { fprintf(stderr, "if ($line == %d) {$a =~ s/lcall/acall/;};\n",yyline); } else { fprintf(stderr, "if ($line == %d) {$a =~ s/ljmp/ajmp/;};\n",yyline); } } return(offset); } void yyerror1(char *s) { yyerror(s, 0, 0,0,0,0,0); } void yyerror2(char *s,long a) { yyerror(s, a, 0,0,0,0,0); } #define yyerror yyerror1 %} %token t_a t_c t_add t_addc t_subb t_anl t_orl t_xrl t_even t_odd t_xcall %token t_anl t_orl t_xrl t_inc t_dec t_clr t_cpl t_rl t_rlc %token t_rr t_rrc t_swap t_da t_dptr t_mul t_ab t_div t_mov t_movc %token t_movx t_push t_pop t_xch t_setb t_jc t_jnc t_jb t_jnb %token t_jbc t_acall t_lcall t_ret t_reti t_ajmp t_ljmp t_sjmp %token t_jmp t_jz t_jnz t_cjne t_djnz t_nop t_val t_name t_bit %token t_r0 t_r1 t_r2 t_r3 t_r4 t_r5 t_r6 t_r7 t_pc t_nl t_xchd t_end t_b %token t_long t_byte t_word t_string t_db t_dl t_dx t_dw t_text t_data %start lines %% lines: line_list end_o ; end_o: | t_end t_nl ; line_list: line | line_list line ; line: t_nl | label { /*if (pass == 1) set_val($1, pc, 0);*/} t_nl | label { /*if (pass == 1) set_val($1, pc, 0);*/ } inst { pc += op_size;} t_nl | inst { pc += op_size; } t_nl | t_name '=' eexp t_nl { if (pass == 2 || valid) set_val((struct dict *)$1, $3, 0); } | t_name '=' bit t_nl { if (pass == 1) ((struct dict *)$1)->bits = 1; } | t_bit '=' bit t_nl { if (pass == 2 && valid) set_val((struct dict *)$1, $3, 1); } | '.' t_even t_nl { if (pc&1) {pc++; if (pass==2)emit1(0);}} | '.' t_odd t_nl { if ((pc&1)==0) {pc++; if (pass==2)emit1(0);}} | '$' '=' eexp { if (!valid) { yyerror("Undefined value in assignment to '.'"); } else { pc = $3; if (pass == 2) set_addr(); } } t_nl | '.' '=' eexp { if (!valid) { yyerror("Undefined value in assignment to '.'"); } else { pc = $3; if (pass == 2) set_addr(); } } t_nl ; label: t_name {new_label((struct dict *)$1); $$ = $1;} | t_name ':' {new_label((struct dict *)$1); $$ = $1;} ; inst: dop t_a ',' reg {P1(1);emit1($1|8|$4);} | dop t_a ',' d256 {P1(2);emit2($1|5,$4);} | dop t_a ',' '@' reg01 {P1(1);emit1($1|6|$5);} | dop t_a ',' '#' immed {P1(2);emit2($1|4,$5);} | sdop d256 ',' t_a {P1(2);emit2($1|2,$2);} | sdop d256 ',' '#' immed {P1(3);emit3($1|3,$2,$5);} | sdop2 t_c ',' bit {P1(2);emit2($1>>8, $4);} | sdop2 t_c ',' '/' bit {P1(2);emit2($1&0xff, $5);} | move | cc | jump | uop reg {P1(1);emit1($1|8|$2);} | uop d256 {P1(2);emit2($1|5,$2);} | uop '@' reg01 {P1(1);emit1($1|6|$3);} | uop t_a {P1(1);emit1($1|4);} | xuop t_a {P1(1);emit1($1);} | misc | {csize = 4;op_size=0;dswap=0;} t_long vlist | {csize = 2;op_size=0;dswap=0;} t_word vlist | {csize = 1;op_size=0;dswap=0;} t_byte vlista | {csize = 4;op_size=0;dswap=0;} t_dl vlist | {csize = 2;op_size=0;dswap=0;} t_dw vlist | {csize = 2;op_size=0;dswap=1;} t_dx vlist {dswap = 0;} | {csize = 1;op_size=0;dswap=0;} t_db vlista | t_text { if (!text) { data_pc = pc; data = 0; pc = text_pc; text = 1; if (pass == 2) set_addr(); } op_size = 0; } | t_data { if (!data) { text_pc = pc; text = 0; pc = data_pc; data = 1; if (pass == 2) set_addr(); } op_size = 0; } ; vlist: vexp | vlist ',' vexp ; vlista: vaexp | vlista ',' vaexp ; vexp: eexp { if (pass == 2) { if (csize == 1) { if ($1 < 0 || $1 > 0xff) yyerror("byte constant too big"); emit1($1); } else if (csize == 2) { if ($1 < 0 || $1 > 0xffff) yyerror("word constant too big"); if (dswap) { emit2($1>>8, $1); } else { emit2($1, $1>>8); } } else { emit2($1, $1>>8); emit2($1>>16, $1>>24); } } pc += csize; } ; vaexp: vexp | t_string { cp = (char *)$1; pc += strlen(cp)+(cp[strlen(cp)-1]&0x80?-1:1); if (pass == 2) { while (*cp && (*cp&0x80) == 0) emit1(*cp++); if (*cp == 0) emit1(0); } free((char *)$1); } ; dop: t_add { $$ = 0x20;} | t_addc { $$ = 0x30;} | t_subb { $$ = 0x90;} | t_anl { $$ = 0x50;} | t_orl { $$ = 0x40;} | t_xrl { $$ = 0x60;} ; sdop: t_anl { $$ = 0x50;} | t_orl { $$ = 0x40;} | t_xrl { $$ = 0x60;} ; sdop2: t_anl { $$ = 0x82b0;} | t_orl { $$ = 0x72c0;} ; uop: t_inc { $$ = 0x00;} | t_dec { $$ = 0x10;} ; xuop: t_clr { $$ = 0xe4;} | t_cpl { $$ = 0xf4;} | t_rl { $$ = 0x23;} | t_rlc { $$ = 0x33;} | t_rr { $$ = 0x03;} | t_rrc { $$ = 0x13;} | t_swap { $$ = 0xc4;} | t_da { $$ = 0xd4;} ; misc: t_inc t_dptr {P1(1);emit1(0xa3);} | t_mul t_ab {P1(1);emit1(0xa4);} | t_div t_ab {P1(1);emit1(0x84);} ; move: t_mov t_a ',' reg {P1(1);emit1(0xe8|$4);} | t_mov t_a ',' d256 {P1(2);emit2(0xe5,$4);} | t_mov t_a ',' '@' reg01 {P1(1);emit1(0xe6|$5);} | t_mov t_a ',' '#' immed {P1(2);emit2(0x74,$5);} | t_mov reg ',' t_a {P1(1);emit1(0xf8|$2);} | t_mov reg ',' d256 {P1(2);emit2(0xa8|$2,$4);} | t_mov reg ',' reg {P1(2);emit2(0xa8|$2,$4);} | t_mov reg ',' '#' immed {P1(2);emit2(0x78|$2,$5);} | t_mov d256 ',' t_a {P1(2);emit2(0xf5,$2);} | t_mov d256 ',' reg {P1(2);emit2(0x88|$4, $2);} | t_mov d256 ',' d256 {P1(3);emit3(0x85,$4,$2);} | t_mov d256 ',' '@' reg01 {P1(2);emit2(0xe6|$5,$2);} | t_mov d256 ',' '#' immed {P1(3);emit3(0x75,$2,$5);} | t_mov '@' reg01 ',' t_a {P1(1);emit1(0xf6|$3);} | t_mov '@' reg01 ',' d256 {P1(2);emit2(0xa6|$3,$5);} | t_mov '@' reg01 ',' '#' immed {P1(2);emit2(0x76|$3,$6);} | t_mov t_dptr ',' '#' immed16 {P1(3);emit3(0x90,$5>>8,$5&0xff);} | t_movc t_a ',' '@' t_a '+' t_dptr {P1(1);emit1(0x93);} | t_movc t_a ',' '@' t_a '+' t_pc {P1(1);emit1(0x83);} | t_movx t_a ',' '@' reg01 {P1(1);emit1(0xe2|$5);} | t_movx t_a ',' '@' t_dptr {P1(1);emit1(0xe0);} | t_movx '@' reg01 ',' t_a {P1(1);emit1(0xf2|$3);} | t_movx '@' t_dptr ',' t_a {P1(1);emit1(0xf0);} | t_push d256 {P1(2);emit2(0xc0,$2);} | t_pop d256 {P1(2);emit2(0xd0,$2);} | t_xch t_a ',' reg {P1(1);emit1(0xc8|$4);} | t_xch t_a ',' d256 {P1(2);emit2(0xc5,$4);} | t_xch t_a ',' '@' reg01 {P1(1);emit1(0xc6|$5);} | t_xchd t_a ',' '@' reg01 {P1(1);emit1(0xd6|$5);} | t_mov t_c ',' bit {P1(2);emit2(0xa2,$4);} | t_mov bit ',' t_c {P1(2);emit2(0x92,$2);} ; cc: t_clr t_c {P1(1);emit1(0xc3);} | t_clr bit {P1(2);emit2(0xc2,$2);} | t_setb t_c {P1(1);emit1(0xd3);} | t_setb bit {P1(2);emit2(0xd2,$2);} | t_cpl t_c {P1(1);emit1(0xb3);} | t_cpl bit {P1(2);emit2(0xb2,$2);} ; jump: t_jc rel {P1(2);emit2(0x40,chrel($2-2));} | t_jnc rel {P1(2);emit2(0x50,chrel($2-2));} | t_jb bit ',' rel {P1(3);emit3(0x20,$2,chrel($4-3));} | t_jnb bit ',' rel {P1(3);emit3(0x30,$2,chrel($4-3));} | t_jbc bit ',' rel {P1(3);emit3(0x10,$2,chrel($4-3));} | t_acall addr16 {P1(2);emit2(0x11|(($2>>3)&0xe0),cha($2,1,2)&0xff);} | t_lcall addr16 {P1(3);emit3(0x12,$2>>8,chl($2,1,2)&0xff);} | t_xcall addr16 {if ((pc&1)==0) {pc++; if (pass==2)emit1(0);} P1(3);emit3(0x12,$2>>8,$2&0xff);} | t_ret {P1(1);emit1(0x22);} | t_reti {P1(1);emit1(0x32);} | t_ajmp addr16 {P1(2);emit2(0x01|(($2>>3)&0xe0),cha($2,0,2)&0xff);} | t_ljmp addr16 {P1(3);emit3(0x02,$2>>8,chl($2,0,2)&0xff);} | t_sjmp rel {P1(2);emit2(0x80,chrel($2-2));} | t_jmp '@' t_a '+' t_dptr {P1(1);emit1(0x73);} | t_jz rel {P1(2);emit2(0x60,chrel($2-2));} | t_jnz rel {P1(2);emit2(0x70,chrel($2-2));} | t_cjne t_a ',' d256 ',' rel {P1(3);emit3(0xb5,$4,chrel($6-3));} | t_cjne t_a ',' '#' immed ',' rel {P1(3);emit3(0xb4,$5,chrel($7-3));} | t_cjne reg ',' '#' immed ',' rel {P1(3);emit3(0xb8|$2,$5,chrel($7-3));} | t_cjne d256 ',' '#' immed ',' rel {P1(3);emit3(0xb8|$2,$5,chrel($7-3));if (pass == 2 && $2 > 7) yyerror("register out of range");} | t_cjne '@' reg01 ',' '#' immed ',' rel {P1(3);emit3(0xb5|$3,$6,chrel($8-3));} | t_djnz reg ',' rel {P1(2);emit2(0xd8|$2,chrel($4-2));} | t_djnz d256 ',' rel {P1(3);emit3(0xd5,$2,chrel($4-3));} | t_nop {P1(1);emit1(0x00);} ; rel: name { $$ = $1-pc; } | name '+' t_val { $$ = $1-pc+$3; } | name '-' t_val { $$ = $1-pc-$3; } | '$' '+' t_val { $$ = 0+$3; } | '$' '-' t_val { $$ = 0-$3; } | '$' { $$ = 0; } | '.' '+' t_val { $$ = 0+$3; } | '.' '-' t_val { $$ = 0-$3; } | '.' { $$ = 0; } ; addr16: name { $$ = $1; } | name '+' t_val { $$ = $1+$3; } | name '-' t_val { $$ = $1-$3; } | '$' { $$ = pc; } | '$' '+' t_val { $$ = pc+$3; } | '$' '-' t_val { $$ = pc-$3; } | '.' { $$ = pc; } | '.' '+' t_val { $$ = pc+$3; } | '.' '-' t_val { $$ = pc-$3; } | t_val { $$ = $1; } ; reg: t_r0 { $$ = 0; } | t_r1 { $$ = 1; } | t_r2 { $$ = 2; } | t_r3 { $$ = 3; } | t_r4 { $$ = 4; } | t_r5 { $$ = 5; } | t_r6 { $$ = 6; } | t_r7 { $$ = 7; } ; reg01: t_r0 { $$ = 0; } | t_r1 { $$ = 1; } | d256 { $$ = $1; if (pass == 2 && $1 > 1) yyerror("register out of range")} ; d256: eexp { $$ = $1&0xff; if (pass == 2 && $1&0xff00) yyerror("Invalid direct address (too big)");} ; immed: eexp { $$ = $1&0xff; if (pass == 2 && $1&0xff00) yyerror("Invalid 8-bit immediate value (too big)");} ; immed16: eexp { $$ = $1&0xffff; } ; eexp: V1 exp { $$ = $2; } ; V1: { valid = 1; } ; exp: exp1 '|' exp { $$ = $1 | $3; } | exp1 { $$ = $1; } ; exp1: exp2 '^' exp1 { $$ = $1 ^ $3; } | exp2 { $$ = $1; } ; exp2: exp2a '&' exp2 { $$ = $1 & $3; } | exp2a { $$ = $1; } ; exp2a: exp3 '<' '<' exp2a { $$ = $1 << $4; } | exp3 '>' '>' exp2a { $$ = $1 >> $4; } | exp3 { $$ = $1; } ; exp3: exp4 '+' exp3 { $$ = $1 + $3; } | exp4 '-' exp3 { $$ = $1 - $3; } | exp4 { $$ = $1; } ; exp4: exp5 '/' exp4 { if ($3 == 0) { $$ = 0; if (pass == 2) yyerror("Divide by 0"); } else { $$ = $1 / $3; } } | exp5 '%' exp4 { if ($3 == 0) { $$ = 0; if (pass == 2) yyerror("Mod by 0"); } else { $$ = $1 % $3; } } | exp5 '*' exp4 { $$ = $1 * $3; } | exp5 { $$ = $1; } ; exp5: t_val { $$ = $1; } | name { $$ = $1; } | '.' { $$ = pc; } | '$' { $$ = pc; } | '-' exp5 { $$ = -$2; } | '~' exp5 { $$ = ~$2; } | '(' eexp ')' { $$ = $2; } ; bit: t_bit { $$ = ((struct dict *)$1)->val; } | t_bit '.' t_val { if (pass == 1) { yyerror("can't take a bit offset on a bit constant"); if ($3 < 0 || $3 > 8) { yyerror("bit offset out of the range 0..7"); } } } | eexp '.' t_val { if (pass == 2) { if ($3 < 0 || $3 > 8) { yyerror("bit offset out of the range 0..7"); } else if ($1 < 0x20 || $1 > 0xff || ($1 > 0x2f && $1 < 0x80) || ($1 >= 0x80 && $1 <= 0xff && $1&0x07)) { yyerror("invalid base for bit offset"); } else { if ($1 >= 0x80) { $$ = $1 | $3; } else { $$ = (($1&0x1f)<<3) | $3; } } } } | eexp '.' t_b { $$ = $1; } ; name: t_name { $$ = ((struct dict *)$1)->val; valid &= ((struct dict *)$1)->valid; if (pass == 2 && !((struct dict *)$1)->valid) { yyerror2("Undefined variable '%s'", (long)((struct dict *)$1)->name); } } | t_b { $$ = 0xf0; } ;