home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * Copyright (c) 1988 by Sozobon, Limited. Author: Joseph M Treat
- *
- * Permission is granted to anyone to use this software for any purpose
- * on any computer system, and to redistribute it freely, with the
- * following restrictions:
- * 1) No charge may be made other than reasonable charges for reproduction.
- * 2) Modified versions must be clearly marked as such.
- * 3) The authors are not responsible for any harmful consequences
- * of using this software, even if they result from defects in it.
- */
-
- #include "jas.h"
-
- #include "parse.h"
-
- int line = 1;
- int sawerror = 0;
- int ignore = 0;
- int funny_state = -1;
-
- jmp_buf YYljbuf;
- jmp_buf YYopbuf;
-
- YYSTYPE yylval;
- int yywidth = 0;
-
- int token = 0;
-
- SYM *cursym = (SYM *) NULL;
-
- extern SYM dot;
- extern long newdot;
-
- extern EXPR Yexpr(), Xexpr(), Aexpr(), Sexpr(),
- Pexpr(), Mexpr(), Uexpr(), Yfactor();
- extern LIST *Yname_list(), *Yexpr_list();
- extern OPERAND *Yoperand();
-
- yyparse()
- {
- token = yylex();
- while ( token ) {
- Yline();
- dot.value = newdot;
- }
- return sawerror;
- }
-
- Yline()
- {
- if ( setjmp( YYljbuf ) ) {
- /*
- * Return here on any call to Yerror to gobble up through NL
- */
- while ( token && token != NL )
- token = yylex();
- if ( token ) {
- line++;
- token = yylex();
- }
- ignore = 0;
- return;
- }
-
- if ( Ylabel_list() )
- Ystatement();
-
- if ( token != NL )
- Yerror( "end of line expected" );
- line++;
- token = yylex();
- ignore = 0;
- }
-
- Ylabel_list()
- {
- while ( token == NAME ) {
- cursym = yylval.sym;
- token = yylex();
- if ( token == _EQU ) {
- EXPR val;
- if ( cursym->flags & (SEGMT|EQUATED) )
- Yerror( "symbol redefinition" );
- token = yylex();
- val = Yexpr();
- if ( val.psym )
- Yerror( "illegal equated expression" );
- cursym->value = val.value;
- cursym->flags |= EQUATED | DEFINED;
- return 0;
- }
- if ( token != COLON )
- Yerror( "missing ':'" );
- if ( cursym->flags & (SEGMT|EQUATED) )
- Yerror( "symbol redefinition" );
- cursym->flags |= ( dot.flags & SEGMT ) | DEFINED;
- cursym->value = dot.value;
- token = yylex();
- }
- return 1;
- }
-
- Ystatement()
- {
- if ( token != NL ) {
- Yinstruction();
- cursym = (SYM *) NULL;
- }
- }
-
- Yinstruction()
- {
- STMT *sp;
- SYM *sym;
- EXPR val;
- register short size;
- register LIST *lp, *xlp;
- extern LIST *Yname_list();
- extern LIST *Yexpr_list();
-
- switch ( token ) {
- default:
- Yerror( "syntax error" );
- break;
- case END:
- token = yylex();
- break;
- case _TEXT:
- chsegmt( TXT );
- token = yylex();
- break;
- case _DATA:
- chsegmt( DAT );
- token = yylex();
- break;
- case _BSS:
- chsegmt( BSS );
- token = yylex();
- break;
- case _GLOBL:
- token = yylex();
- lp = Yname_list();
- for ( ; lp; lp = xlp ) {
- xlp = lp->next;
- lp->u.sym->flags |= GLOBAL | DEFINED;
- free( (char *) lp );
- }
- break;
- case _DC:
- size = yywidth;
- if ( size == 0 )
- Yerror( ".dc must have width specifier" );
- token = yylex();
- lp = Yexpr_list();
-
- if ( size != 8 ) {
- if ( newdot & 1 ) {
- zeros( 1L );
- if ( cursym != (SYM *) NULL )
- cursym->value = newdot;
- }
- }
- for ( ; lp; lp = xlp ) {
- xlp = lp->next;
- generate(size, GENRELOC, lp->u.val.value, lp->u.sym );
- free( (char *) lp );
- }
- break;
- case _ORG:
- token = yylex();
- val = Yexpr();
- if ( val.psym )
- Yerror( "illegal use of symbol in expression" );
- if ( val.value < newdot )
- Yerror( "attempt to move current location backward" );
- if ( val.value > newdot ) {
- if ( newdot & 1 )
- zeros( 1L );
- if ( val.value > newdot )
- zeros( val.value - newdot );
- }
- break;
- case _DS:
- size = yywidth;
- if ( size == 0 )
- Yerror( ".ds must have width specifier" );
- token = yylex();
- val = Yexpr();
- if ( size != 8 ) {
- if ( newdot & 1 ) {
- zeros( 1L );
- if ( cursym != (SYM *) NULL )
- cursym->value = newdot;
- }
- }
- if ( val.psym )
- Yerror( "illegal use of symbol in expression" );
- zeros( val.value * (size/8) );
- break;
- case _EVEN:
- if ( newdot & 1 ) {
- zeros( 1L );
- if ( cursym != (SYM *) NULL )
- cursym->value = newdot;
- }
- token = yylex();
- break;
- case _COMM:
- if ( (token = yylex()) != NAME )
- Yerror( "missing label" );
- sym = yylval.sym;
- if ( sym->flags & (SEGMT|EQUATED) )
- Yerror( "symbol redefinition" );
- if ( (token = yylex()) != COMMA )
- Yerror( "missing ','" );
- token = yylex();
- val = Yexpr();
- sym->flags |= EXTERN | DEFINED;
- sym->value = val.value;
- break;
- case INSTR:
- sp = yylval.stmt;
- sp->op0 = sp->op1 = (OPERAND *) NULL;
- token = yylex();
- if ( token != NL ) {
- sp->op0 = Yoperand();
- if ( token == COMMA ) {
- token = yylex();
- sp->op1 = Yoperand();
- }
- }
- geninst( sp );
- break;
- }
- }
-
- LIST *
- Yname_list()
- {
- register LIST *lp, *xlp;
-
- if ( token != NAME )
- Yerror( "label expected" );
- lp = xlp = ALLO(LIST);
- xlp->next = (LIST *) NULL;
- xlp->u.sym = yylval.sym;
- token = yylex();
- while ( token == COMMA ) {
- if ( (token = yylex()) != NAME )
- Yerror( "label expected" );
- xlp->next = ALLO(LIST);
- xlp = xlp->next;
- xlp->next = (LIST *) NULL;
- xlp->u.sym = yylval.sym;
- token = yylex();
- }
- return lp;
- }
-
- LIST *
- Yexpr_list()
- {
- EXPR val;
- register LIST *lp;
- LIST *xlp, *slp;
- extern LIST *make_slist();
-
- if ( token == STRING ) {
- lp = make_slist( &xlp, yylval.str );
- token = yylex();
- free( yylval.str );
- } else {
- val = Yexpr();
- lp = xlp = ALLO(LIST);
- xlp->next = (LIST *) NULL;
- xlp->u.val = val;
- }
- while ( token == COMMA ) {
- token = yylex();
- if ( token == STRING ) {
- xlp->next = make_slist( &slp, yylval.str );
- xlp = slp;
- token = yylex();
- free( yylval.str );
- } else {
- val = Yexpr();
- xlp->next = ALLO(LIST);
- xlp = xlp->next;
- xlp->next = (LIST *) NULL;
- xlp->u.val = val;
- }
- }
- return lp;
- }
-
- LIST *
- make_slist( last, string )
- LIST **last;
- char *string;
- {
- char *cp;
- LIST *lp, *xlp;
- EXPR val;
-
- lp = xlp = (LIST *) NULL;
-
- for ( cp = string; *cp; cp++ ) {
- int ch;
-
- if ( *cp == '\\' ) {
- switch ( cp[1] ) {
- case 'n': ch = '\n'; break;
- case 't': ch = '\t'; break;
- case 'r': ch = '\r'; break;
- case 'b': ch = '\b'; break;
- case '0': ch = '\0'; break;
- default: ch = cp[1]; break;
- }
- cp++;
- } else {
- ch = *cp;
- }
- if ( lp == (LIST *) NULL ) {
- lp = xlp = ALLO(LIST);
- xlp->next = (LIST *) NULL;
- } else {
- xlp->next = ALLO(LIST);
- xlp = xlp->next;
- xlp->next = (LIST *) NULL;
- }
- xlp->u.val.psym = (SYM *) NULL;
- xlp->u.val.value = ch;
- }
-
- *last = xlp;
- return lp;
- }
-
- OPERAND *
- Yoperand()
- {
- register OPERAND *op;
- register int reg, inx;
- EXPR val;
-
- op = ALLO(OPERAND);
- switch ( token ) {
- case SREG:
- op->mode = yylval.val;
- token = yylex();
- break;
- case REG:
- op->mode = yylval.val < 8 ? O_DN : O_AN;
- op->reg = reg = yylval.val;
- token = yylex();
- if ( token == MINUS || token == DIV ) {
- /*
- * we have a register mask list
- */
- op->mode = O_REGS;
- op->expr.value = 1L << reg;
- while ( token == MINUS || token == DIV ) {
- int tok = token;
-
- token = yylex();
- inx = yylval.val;
- if ( token != REG )
- Yerror("invalid register list");
- if ( tok == DIV ) {
- op->expr.value |= (1L << inx);
- reg = inx;
- } else {
- int i;
-
- if ( inx < reg )
- Yerror("invalid register list");
- for ( i = reg+1; i <= inx; i++ )
- op->expr.value |= (1L << i);
- }
- token = yylex();
- if ( tok == MINUS && token == MINUS )
- Yerror("invalid register list");
- }
- }
- break;
- case LP:
- if ( (token = yylex()) != REG )
- Yerror( "missing register" );
- reg = yylval.val;
- if ( (token = yylex()) != RP )
- Yerror( "missing ')'" );
- token = yylex();
- if ( token == PLUS ) {
- op->mode = O_POST;
- op->reg = reg;
- token = yylex();
- } else {
- op->mode = O_INDR;
- op->reg = reg;
- }
- break;
- default:
- funny_state = 0;
- if ( setjmp( YYopbuf ) ) {
- /*
- * Yexpr() saw MINUS LP REG
- */
- reg = yylval.val;
- if ( (token = yylex()) != RP )
- Yerror( "missing ')'" );
- op->mode = O_PRE;
- op->reg = reg;
- token = yylex();
- funny_state = -1;
- break;
- }
- val = Yexpr();
- funny_state = -1;
- if ( token != LP ) {
- op->mode = O_ABS;
- op->expr = val;
- break;
- }
- token = yylex();
- if ( token == REG ) {
- reg = yylval.val;
- if ( (token = yylex()) == COMMA ) {
- if ( (token = yylex()) != REG )
- Yerror( "missing register" );
- inx = yylval.val;
- if ( yywidth == 8 )
- Yerror( "index reg can't be byte" );
- if ( yywidth == 32 )
- inx |= 0x10;
- if ( (token = yylex()) != RP )
- Yerror( "missing ')'" );
- op->mode = O_INDX;
- op->reg = reg;
- op->inx = inx;
- op->expr = val;
- token = yylex();
- } else {
- if ( token != RP )
- Yerror( "missing ')'" );
- op->mode = O_DISP;
- op->reg = reg;
- op->expr = val;
- token = yylex();
- }
- } else if ( token == PC ) {
- if ( (token = yylex()) == COMMA ) {
- if ( (token = yylex()) != REG )
- Yerror( "missing register" );
- inx = yylval.val;
- if ( yywidth == 8 )
- Yerror( "index reg can't be byte" );
- if ( yywidth == 32 )
- inx |= 0x10;
- if ( (token = yylex()) != RP )
- Yerror( "missing ')'" );
- op->mode = O_PCIX;
- op->inx = inx;
- op->expr = val;
- token = yylex();
- } else {
- if ( token != RP )
- Yerror( "missing ')'" );
- op->mode = O_PCRL;
- op->expr = val;
- token = yylex();
- }
- } else
- Yerror( "register or pc expected" );
- break;
- case POUND:
- token = yylex();
- val = Yexpr();
- op->mode = O_IMM;
- op->expr = val;
- break;
- }
- return op;
- }
-
- EXPR
- Yexpr()
- {
- EXPR val1, val2;
-
- val1 = Xexpr();
- while ( token == OR ) {
- funny_state = -1;
- token = yylex();
- val2 = Xexpr();
- if ( val1.psym || val2.psym )
- Yerror( "illegal use of symbol in expression" );
- val1.value |= val2.value;
- }
- return val1;
- }
-
- EXPR
- Xexpr()
- {
- EXPR val1, val2;
-
- val1 = Aexpr();
- while ( token == XOR ) {
- funny_state = -1;
- token = yylex();
- val2 = Aexpr();
- if ( val1.psym || val2.psym )
- Yerror( "illegal use of symbol in expression" );
- val1.value ^= val2.value;
- }
- return val1;
- }
-
- EXPR
- Aexpr()
- {
- EXPR val1, val2;
-
- val1 = Sexpr();
- while ( token == AND ) {
- funny_state = -1;
- token = yylex();
- val2 = Sexpr();
- if ( val1.psym || val2.psym )
- Yerror( "illegal use of symbol in expression" );
- val1.value &= val2.value;
- }
- return val1;
- }
-
- EXPR
- Sexpr()
- {
- register int op;
- EXPR val1, val2;
-
- val1 = Pexpr();
- while ( token == LSH || token == RSH ) {
- op = token;
- funny_state = -1;
- token = yylex();
- val2 = Pexpr();
- if ( val1.psym || val2.psym )
- Yerror( "illegal use of symbol in expression" );
- if ( op == LSH )
- val1.value <<= val2.value;
- else
- val1.value >>= val2.value;
- }
- return val1;
- }
-
- EXPR
- Pexpr()
- {
- register int op;
- EXPR val1, val2;
-
- val1 = Mexpr();
- while ( token == PLUS || token == MINUS ) {
- op = token;
- funny_state = -1;
- token = yylex();
- val2 = Mexpr();
- if ( op == PLUS ) {
- if ( val1.psym && val2.psym )
- Yerror( "illegal use of symbol in expression" );
- if ( val2.psym )
- val1.psym = val2.psym;
- val1.value += val2.value;
- } else {
- if ( val2.psym )
- Yerror( "illegal use of symbol in expression" );
- val1.value -= val2.value;
- }
- }
- return val1;
- }
-
- EXPR
- Mexpr()
- {
- register int op;
- EXPR val1, val2;
- jmp_buf oldYYljbuf;
-
- val1 = Uexpr();
- while ( token == STAR || token == DIV || token == MOD ) {
- op = token;
- funny_state = -1;
- token = yylex();
- val2 = Uexpr();
- if ( val1.psym || val2.psym )
- Yerror( "illegal use of symbol in expression" );
- if ( op == DIV ) {
- if ( val2.value == 0L )
- Yerror( "divison by zero" );
- val1.value /= val2.value;
- } else if ( op == MOD ) {
- if ( val2.value == 0L )
- Yerror( "modulo by zero" );
- val1.value %= val2.value;
- } else {
- val1.value *= val2.value;
- }
- }
- return val1;
- }
-
- EXPR
- Uexpr()
- {
- EXPR val;
-
- switch ( token ) {
- case MINUS:
- if ( funny_state == 0 )
- funny_state = 1;
- else
- funny_state = -1;
- token = yylex();
- val = Yfactor();
- val.value = - val.value;
- if ( val.psym )
- Yerror( "illegal use of symbol in expression" );
- break;
- case NOT:
- funny_state = -1;
- token = yylex();
- val = Yfactor();
- if ( val.psym )
- Yerror( "illegal use of symbol in expression" );
- val.value = - val.value;
- break;
- default:
- val = Yfactor();
- break;
- }
- return val;
- }
-
- EXPR
- Yfactor()
- {
- EXPR val;
-
- switch ( token ) {
- case NUMBER:
- funny_state = -1;
- val.psym = (SYM *) NULL;
- val.value = yylval.val;
- break;
- case NAME:
- funny_state = -1;
- if ( yylval.sym->flags & EQUATED ) {
- val.psym = (SYM *) NULL;
- val.value = yylval.sym->value;
- break;
- }
- val.psym = yylval.sym;
- val.value = 0L;
- break;
- case LP:
- if ( funny_state == 1 )
- funny_state = 2;
- else
- funny_state = -1;
- token = yylex();
- val = Yexpr();
- if ( token != RP )
- Yerror( "missing ')'" );
- break;
- case REG:
- if ( funny_state == 2 ) {
- longjmp( YYopbuf, 1 );
- }
- default:
- Yerror( "illegal expression" );
- }
- token = yylex();
- return val;
- }
-
- Yerror( s )
- char *s;
- {
- if (! ignore) {
- fprintf( stderr, "jas: line %d ( %s )\n", line, s );
- ignore = 1;
- }
- sawerror = 1;
- funny_state = -1;
- longjmp( YYljbuf, 1 );
- }
-