示例#1
0
void LstWrite( enum lsttype type, uint_32 oldofs, void *value )
/*************************************************************/
{
    uint_32 newofs;
    struct asym *sym = value;
    int     len;
    int     len2;
    int     idx;
    int     srcfile;
    char    *p1;
    char    *p2;
    char    *pSrcline;
    struct lstleft *pll;
    struct lstleft ll;
    //char    buffer2[MAX_LINE_LEN]; /* stores text macro value */

    if ( ModuleInfo.list == FALSE || CurrFile[LST] == NULL || ( ModuleInfo.line_flags & LOF_LISTED ) )
        return;
    if ( ModuleInfo.GeneratedCode && ( ModuleInfo.list_generated_code == FALSE ) )
        return;
    if ( MacroLevel ) {
        switch ( ModuleInfo.list_macro ) {
        case LM_NOLISTMACRO:
            return;
        case LM_LISTMACRO:
            /* todo: filter certain macro lines */
            break;
        }
    }

    ModuleInfo.line_flags |= LOF_LISTED;

    DebugMsg1(("LstWrite( %u, %" I32_SPEC "u ): enter [ pos=%" I32_SPEC "u, GeneratedCode=%u, MacroLevel=%u ]\n", type, oldofs, list_pos, ModuleInfo.GeneratedCode, MacroLevel ));
    pSrcline = CurrSource;
#if FASTPASS
    if ( ( Parse_Pass > PASS_1 ) && UseSavedState ) {
        if ( ModuleInfo.GeneratedCode == 0 ) {
            if ( !( ModuleInfo.line_flags & LOF_SKIPPOS ) )
                list_pos = LineStoreCurr->list_pos;
#if USELSLINE /* either use CurrSource + CurrComment or LineStoreCurr->line (see assemble.c, OnePass() */
            pSrcline = LineStoreCurr->line;
            if ( ModuleInfo.CurrComment ) { /* if comment was removed, readd it! */
                *( LineStoreCurr->line + strlen( LineStoreCurr->line ) ) = ';';
                ModuleInfo.CurrComment = NULL;
            }
#endif
            DebugMsg1(("LstWrite: Pass=%u, stored pos=%" I32_SPEC "u\n", Parse_Pass+1, list_pos ));
        }
        fseek( CurrFile[LST], list_pos, SEEK_SET );
    }
#endif

    ll.next = NULL;
    memset( ll.buffer, ' ', sizeof( ll.buffer ) );
    srcfile = get_curr_srcfile();

    switch ( type ) {
    case LSTTYPE_DATA:
        if ( Parse_Pass == PASS_1 && Options.first_pass_listing == FALSE ) {
            break;
        }
        /* no break */
    case LSTTYPE_CODE:
        newofs = GetCurrOffset();
        sprintf( ll.buffer, "%08" I32_SPEC "X", oldofs );
        ll.buffer[OFSSIZE] = ' ';

        if ( CurrSeg == NULL )
            break;
        //if ( write_to_file == FALSE )
        if ( Options.first_pass_listing ) {
            if ( Parse_Pass > PASS_1 )
                break;
#ifdef DEBUG_OUT
        } else if ( Options.max_passes == 1 ) {
            ; /* write a listing in pass 1 */
#endif
        } else if ( Parse_Pass == PASS_1 )  /* changed v1.96 */
            break;

        len = CODEBYTES;
        p2 = ll.buffer + OFSSIZE + 2;

        if ( CurrSeg->e.seginfo->CodeBuffer == NULL ||
            CurrSeg->e.seginfo->written == FALSE ) {
            while ( oldofs < newofs && len ) {
                *p2++ = '0';
                *p2++ = '0';
                oldofs++;
                len--;
            }
            break;
        }

        /* OMF hold just a small buffer for one LEDATA record */
        /* if it has been flushed, use LastCodeBufSize */
        idx = (CurrSeg->e.seginfo->current_loc - CurrSeg->e.seginfo->start_loc)
            - (newofs - oldofs);
        if ( Options.output_format == OFORMAT_OMF ) {
            /* v2.11: additional check to make the hack more robust [ test case:  db 800000h dup (0) ] */
            if ( ( idx+LastCodeBufSize ) < 0 )
                break; /* just exit. The code bytes area will remain empty */
            while ( idx < 0 && len ) {
                sprintf( p2, "%02X", CurrSeg->e.seginfo->CodeBuffer[idx+LastCodeBufSize] );
                p2 += 2;
                idx++;
                oldofs++;
                len--;
            }
        } else if (idx < 0)
            idx = 0;

        while ( oldofs < newofs && len ) {
            sprintf( p2, "%02X", CurrSeg->e.seginfo->CodeBuffer[idx] );
            p2 += 2;
            idx++;
            oldofs++;
            len--;
        }
        *p2 = ' ';
        break;
    case LSTTYPE_EQUATE:
        /* v2.10: display current offset if equate is an alias for a label in this segment */
        idx = 1;
        if ( sym->segment && sym->segment == &CurrSeg->sym ) {
            sprintf( ll.buffer, "%08" I32_SPEC "X", GetCurrOffset() );
            idx = 10;
        }
        ll.buffer[idx] = '=';
#if AMD64_SUPPORT
        if ( sym->value3264 != 0 && ( sym->value3264 != -1 || sym->value >= 0 ) )
            sprintf( &ll.buffer[idx+2], "%-" PREFFMTSTR I64_SPEC "X", (uint_64)sym->value + ( (uint_64)sym->value3264 << 32 ) );
        else
#endif
            sprintf( &ll.buffer[idx+2], "%-" PREFFMTSTR I32_SPEC "X", sym->value );
        ll.buffer[28] = ' ';
        break;
    case LSTTYPE_TMACRO:
        ll.buffer[1] = '=';
        //GetLiteralValue( buffer2, sym->string_ptr );
        //strcpy( buffer2, sym->string_ptr );
        for ( p1 = sym->string_ptr, p2 = &ll.buffer[3], pll = &ll; *p1; ) {
            if ( p2 >= &pll->buffer[28] ) {
                struct lstleft *next = myalloca( sizeof( struct lstleft ) );
                pll->next = next;
                pll = next;
                pll->next = NULL;
                memset( pll->buffer, ' ', sizeof( pll->buffer) );
                p2 = &pll->buffer[3];
            }
            *p2++ = *p1++;
        }
        break;
    case LSTTYPE_MACROLINE:
        ll.buffer[1] = '>';
        pSrcline = value;
        break;
    case LSTTYPE_LABEL:
        oldofs = GetCurrOffset();
        /* no break */
    case LSTTYPE_STRUCT:
        sprintf( ll.buffer, "%08" I32_SPEC "X", oldofs );
        ll.buffer[8] = ' ';
        break;
    case LSTTYPE_DIRECTIVE:
        if ( CurrSeg || value ) {
            sprintf( ll.buffer, "%08" I32_SPEC "X", oldofs );
            ll.buffer[8] = ' ';
        }
        break;
    default: /* LSTTYPE_MACRO */
        if ( *pSrcline == NULLC && ModuleInfo.CurrComment == NULL && srcfile == ModuleInfo.srcfile ) {
            DebugMsg1(("LstWrite: type=%u, writing CRLF\n", type ));
            fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
            list_pos += NLSIZ;
            return;
        }
        break;
    }

#if FASTPASS
    if ( Parse_Pass == PASS_1 || UseSavedState == FALSE ) {
#endif
        idx = sizeof( ll.buffer );
        if ( ModuleInfo.GeneratedCode )
            ll.buffer[28] = '*';
        if ( MacroLevel ) {
            len = sprintf( &ll.buffer[29], "%u", MacroLevel );
            ll.buffer[29+len] = ' ';
        }
        if ( srcfile != ModuleInfo.srcfile ) {
            ll.buffer[30] = 'C';
        }
#ifdef DEBUG_OUT
        ll.last = NULLC;
#endif
#if FASTPASS
    } else {
        idx = OFSSIZE + 2 + 2 * CODEBYTES;
#ifdef DEBUG_OUT
        ll.buffer[idx] = NULLC;
#endif
    }
#endif
    fwrite( ll.buffer, 1, idx, CurrFile[LST] );

    len = strlen( pSrcline );
    len2 = ( ModuleInfo.CurrComment ? strlen( ModuleInfo.CurrComment ) : 0 );

    list_pos += sizeof( ll.buffer ) + len + len2 + NLSIZ;
    DebugMsg1(("LstWrite: writing (%u b) >%s< [%u/%u], new pos=%" I32_SPEC "u\n", idx, ll.buffer, len, len2, list_pos ));

    /* write source and comment part */
#if FASTPASS
    if ( Parse_Pass == PASS_1 || UseSavedState == FALSE ) {
#endif
        if ( len )
            fwrite( pSrcline, 1, len, CurrFile[LST] );
        if ( len2 ) {
            fwrite( ModuleInfo.CurrComment, 1, len2, CurrFile[LST] );
            DebugMsg1(("LstWrite: writing (%u b) >%s%s<\n", len + len2 + NLSIZ, pSrcline, ModuleInfo.CurrComment ));
        }
#ifdef DEBUG_OUT
        else DebugMsg1(("LstWrite: writing (%u b) >%s<\n", len + NLSIZ, pSrcline ));
#endif
        fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
#if FASTPASS
    }
#endif

    /* write optional additional lines.
     * currently works in pass one only.
     */
    for ( pll = ll.next; pll; pll = pll->next ) {
        fwrite( pll->buffer, 1, 32, CurrFile[LST] );
        fwrite( NLSTR, 1, NLSIZ, CurrFile[LST] );
        list_pos += 32 + NLSIZ;
        DebugMsg1(("LstWrite: additional line >%s<, new pos=%" I32_SPEC "u\n", pll->buffer, list_pos ));
    }
    return;
}
示例#2
0
文件: loop.c 项目: JWasm/JWasm
ret_code LoopDirective( int i, struct asm_tok tokenarray[] )
/**********************************************************/
{
    int directive = tokenarray[i].tokval;
    int arg_loc;
    int len;
    //int skipcomma;
    char *parmstring;
    char *ptr;
    struct dsym *macro;
    bool is_exitm;
    struct expr opnd;
    struct macro_info macinfo;
    struct dsym tmpmacro;
#ifdef DEBUG_OUT
    uint_32 count = 0;
#endif
    /* v2.08: use myalloca() to get space to store the argument */
    //char line[MAX_LINE_LEN];
    char buffer[4];

    DebugMsg1(("LoopDirective(%s) enter\n", GetResWName( directive, NULL ) ));

    i++; /* skip directive */
    if ( ModuleInfo.list == TRUE ) LstWriteSrcLine();

    switch ( directive ) {
    case T_WHILE:
        arg_loc = i;
    /* no break */
    case T_REPT:
    case T_REPEAT:
        /* the expression is "critical", that is, no forward
         * referenced symbols may be used here!
         */
        if ( EvalOperand( &i, tokenarray, Token_Count, &opnd, EXPF_NOUNDEF ) == ERROR ) {
            opnd.value = 0;
            i = Token_Count;
        } else if ( opnd.kind != EXPR_CONST ) { /* syntax <REPEAT|WHILE 'A'> is valid! */
            DebugMsg(( "LoopDirective(%s): invalid argument type %u\n", GetResWName( directive, NULL ), opnd.kind ));
            EmitError( CONSTANT_EXPECTED );
            opnd.value = 0;
        } else if( tokenarray[i].token != T_FINAL ) {
            EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos );
            /* v2.09: don't exit, the macro lines must be read first. */
            //return( ERROR );
            opnd.value = 0;
        }
        break;
    default: /* FOR, FORC, IRP, IRPC */
        /* get the formal parameter and the argument list */
        /* the format parameter will become a macro parameter, so it can
         * be a simple T_ID, but also an instruction or something else.
         * v2.02: And it can begin with a '.'!
         */
        if( tokenarray[i].token == T_FINAL ) {
            return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i-1].tokpos ) );
        }
        /* v2.02: allow parameter name to begin with a '.' */
        //c = *tokenarray[i].string_ptr;
        //if( ( is_valid_id_char(c) == FALSE ) || ( isdigit(c) == TRUE ) ) {
        if( is_valid_id_first_char( *tokenarray[i].string_ptr ) == FALSE ) {
            DebugMsg(( "LoopDirective(FOR/FORC): token %s is not a valid parameter name\n", tokenarray[i].string_ptr ));
            return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) );
        }
        arg_loc = i;
        i++;

        if( directive == T_FORC || directive == T_IRPC ) {
            if( tokenarray[i].token != T_COMMA ) {
                return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) );
            }
            i++;
            /* FORC/IRPC accepts anything as "argument list", even nothing! */
            if( tokenarray[i].token == T_STRING && tokenarray[i].string_delim == '<' ) {
                len = tokenarray[i+1].tokpos - (tokenarray[i].tokpos+1);
                parmstring = myalloca( len );
                //GetLiteralValue( parmstring, tokenarray[i].string_ptr );
                memcpy( parmstring, tokenarray[i].tokpos+1, len );
                while( *(parmstring+len-1) != '>' ) len--;
                *(parmstring+len-1) = NULLC;
                /* v2.02: if there's additional stuff behind the <> literal,
                 * it's an error!
                 */
                if ( tokenarray[i+1].token != T_FINAL )
                    EmitErr( SYNTAX_ERROR_EX, tokenarray[i+1].tokpos );
            } else {
                char *ptr2;
                ptr = tokenarray[i].tokpos;
                ptr2 = ptr;
                /* this is what Masm does: use the string until a space
                 * is detected. Anything beyond the space is ignored.
                 */
                while ( *ptr2 && ( isspace( *ptr2 ) == FALSE ) )
                    ptr2++;
                len = ptr2 - ptr;
                parmstring = myalloca( len + 1 );
                memcpy( parmstring, ptr, len );
                *(parmstring+len) = NULLC;
            }
        } else {
            /* for FOR/IRP, skip everything between the name and the comma!
             * these items will be stored as (first) macro parameter.
             * for example, valid syntax is:
             * FOR xxx,<a, ...>
             * FOR xxx:REQ,<a, ...>
             */
            while ( tokenarray[i].token != T_FINAL && tokenarray[i].token != T_COMMA )
                i++;
            if( tokenarray[i].token != T_COMMA ) {
                return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) );
            }
            i++;
            /* FOR/IRP accepts a literal enclosed in <> only */
            if( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
                return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) );
            }
            /* v2.03: also ensure that the literal is the last item */
            if( tokenarray[i+1].token != T_FINAL ) {
                return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i+1].tokpos ) );
            }
            /* v2.08: use myalloca() instead of a fixed-length buffer.
             * the loop directives are often nested, they call RunMacro()
             * and hence should be careful with stack usage because of JWASMR!
             */
            //parmstring = myalloca( tokenarray[i].stringlen + 1 );
            /* v2.0: use GetLiteralValue() instead of memcpy!!! */
            //memcpy( line, tokenarray[i].string_ptr, tokenarray[i].stringlen + 1 );
            //GetLiteralValue( parmstring, tokenarray[i].string_ptr );
            parmstring = tokenarray[i].string_ptr;
            DebugMsg1(("LoopDirective(FOR): param string >%s<\n", parmstring));
        }
        /* to run StoreMacro(), tokenarray must be setup correctly. */
        /* clear contents beginning with the comma! */
        i--;
        tokenarray[i].token = T_FINAL;
        Token_Count = i;
        i = arg_loc;
    }

    /* now make a temporary macro */
    macro = &tmpmacro;
    memset( &tmpmacro, 0, sizeof(tmpmacro) );
    tmpmacro.sym.name = "";
    tmpmacro.e.macroinfo = &macinfo;
    memset( &macinfo, 0, sizeof(macinfo) );
    macinfo.srcfile = get_curr_srcfile();

#if 0 //DEBUG_OUT
    if ( directive ==  T_WHILE )
        tmpmacro.sym.name = "<WHILE>";
    else if ( directive == T_REPEAT || directive == T_REPT )
        tmpmacro.sym.name = "<REPT>";
    else if ( directive == T_FORC || directive == T_IRPC )
        tmpmacro.sym.name = "<FORC>";
    else
        tmpmacro.sym.name = "<FOR>";
#endif

    DebugMsg1(("LoopDirective(%s): calling StoreMacro\n", GetResWName( directive, NULL )));
    if( StoreMacro( macro, i, tokenarray, TRUE ) == ERROR ) {
        ReleaseMacroData( macro );
        return( ERROR );
    }
    /* EXITM <> is allowed inside a macro loop.
     * This doesn't make the loop a macro function, reset the bit!
     */
    macro->sym.isfunc = FALSE;

    /* now run the just created macro in a loop */

    /* don't run the macro if there are no lines (macroinfo->data == NULL)!
     * this isn't exactly what Masm does; an empty 'WHILE 1'
     * will loop "forever" in Masm,
     */
    if ( macinfo.data ) /* added in v2.01 */
        switch ( directive ) {
        case T_REPEAT:
        case T_REPT:
            /* negative repeat counts are accepted and are treated like 0 */
            for ( ; macro->sym.value < opnd.value; macro->sym.value++ ) {
                /* v2.10: Token_Count becomes volatile if MF_NOSAVE is set */
                tokenarray[0].token = T_FINAL;
                Token_Count = 0;
                //RunMacro( macro, Token_Count, tokenarray, NULL, MF_NOSAVE, &is_exitm );
                RunMacro( macro, 0, tokenarray, NULL, MF_NOSAVE, &is_exitm );
                if ( is_exitm )
                    break;
                DebugMsg1(("LoopDirective REPT: iteration=%" I32_SPEC "u\n", ++count ));
            }
            break;
        case T_WHILE:
            while ( opnd.kind == EXPR_CONST && opnd.value != 0 ) {
                DebugMsg1(("LoopDirective WHILE: cnt=%u\n", count++ ));
                RunMacro( macro, Token_Count, tokenarray, NULL, 0, &is_exitm );
                if ( is_exitm )
                    break;
                i = arg_loc;
                if ( EvalOperand( &i, tokenarray, Token_Count, &opnd, 0 ) == ERROR )
                    break;
                macro->sym.value++;
            }
            break;
        case T_FORC:
        case T_IRPC:
            for( ptr = parmstring; *ptr; ptr++, macro->sym.value++ ) {
                tokenarray[0].token = T_STRING;
                tokenarray[0].string_delim = NULLC;
                tokenarray[0].string_ptr = buffer;
                tokenarray[0].tokpos = buffer;
                tokenarray[1].token = T_FINAL;
                buffer[2] = NULLC;
                Token_Count = 1;
                if ( *ptr == '!' ) {
                    buffer[0] = *ptr++;
                    buffer[1] = *ptr;
                    if ( *ptr == NULLC ) /* ensure the macro won't go beyond the 00 */
                        ptr--;
                    tokenarray[0].stringlen = 2;
                    tokenarray[1].tokpos = buffer+2;
                } else if ( isspace( *ptr ) ) {
                    buffer[0] = '!';
                    buffer[1] = *ptr;
                    tokenarray[0].stringlen = 2;
                    tokenarray[1].tokpos = buffer+2;
                } else {
                    buffer[0] = *ptr;
                    tokenarray[0].stringlen = 1;
                    tokenarray[1].tokpos = buffer+1;
                    buffer[1] = NULLC;
                }
                RunMacro( macro, 0, tokenarray, NULL, MF_NOSAVE, &is_exitm );
                if ( is_exitm )
                    break;
                DebugMsg1(("LoopDirective FORC: call RunMacro(), cnt=%" I32_SPEC "u, param=>%s<\n", count++, buffer ));
            }
            break;
        default: /* T_FOR, T_IRP */
            i = Token_Count + 1;
            Token_Count = Tokenize( parmstring, i, tokenarray, TOK_RESCAN | TOK_NOCURLBRACES );
            DebugMsg1(("LoopDirective FOR: full param=>%s<\n", tokenarray[i].tokpos ));

            /* v2.09: if a trailing comma is followed by white space(s), add a blank token */
            if ( i != Token_Count && tokenarray[Token_Count-1].token == T_COMMA &&
                    *(tokenarray[Token_Count-1].tokpos+1) ) {
                tokenarray[Token_Count].token = T_STRING;
                tokenarray[Token_Count].string_delim = NULLC;
                tokenarray[Token_Count].stringlen = strlen( tokenarray[Token_Count].tokpos );
                tokenarray[Token_Count+1].tokpos = tokenarray[Token_Count].tokpos + tokenarray[Token_Count].stringlen;
                Token_Count++;
                tokenarray[Token_Count].token = T_FINAL;
            }

            /* a FOR/IRP parameter can be a macro function call */
            /* that's why the macro calls must be run synchronously */
            /* v2.05: reset an optional VARARG attribute for the macro
             * parameter.
             * take care of a trailing comma, this is to make another
             * RunMacro() call with a "blank" argument.
             */
            macro->sym.mac_vararg = FALSE;
            /* v2.09: flag MF_IGNARGS introduced. This allows RunMacro() to
             * parse the full argument and trigger macro expansion if necessary.
             * No need anymore to count commas here. */
            for( ; i < Token_Count; i++, macro->sym.value++ ) {
                DebugMsg1(("LoopDirective FOR: cnt=%" I32_SPEC "u, calling RunMacro( param=>%s< )\n", count++, tokenarray[i].tokpos ));
                i = RunMacro( macro, i, tokenarray, NULL, MF_IGNARGS, &is_exitm );
                if ( i < 0 || is_exitm )
                    break;
            }
        }
    ReleaseMacroData( macro );
    DebugMsg1(("LoopDirective(%s) exit\n", GetResWName( directive, NULL ) ));
    return( NOT_ERROR );
}