jwasm/condasm.c
Serg Stetsuk 9f257e0b33 .errdef/.errndef with or without custom message
GetErrText is not usable 'cause it overwrites StringBufferEnd. So we
must append text to StringBufferEnd. Not all checks as in GetErrText
are performed. So we have side effect: message can be in angle
braces or in quotes too.

Fixes #184.
2017-03-06 20:03:17 +04:00

676 lines
25 KiB
C

/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: JWasm conditional processing routines. Handles directives
* [ELSE]IF[E], ELSE, ENDIF
* [ELSE]IFB, [ELSE]IFNB
* [ELSE]IFDEF, [ELSE]IFNDEF
* [ELSE]IFDIF[I], [ELSE]IFIDN[I]
* [ELSE]IF1, [ELSE]IF2
* .ERR, .ERRNZ, .ERRE
* .ERRB, .ERRNB
* .ERRDEF, .ERRNDEF
* .ERRDIF[I], .ERRIDN[I]
* .ERR1, .ERR2
****************************************************************************/
#include <ctype.h>
#include "globals.h"
#include "parser.h"
#include "condasm.h"
#include "reswords.h"
#include "expreval.h"
#include "listing.h"
#include "input.h"
#include "macro.h"
#include "types.h"
#include "fastpass.h"
/*
the current if-block can be in one of 3 states:
state assembly possible state change to
---------------------------------------------------------
inactive off active
active on done
done off -
--------------------------------------------------------
up to v2.04, there was a fourth state:
condition check on active, inactive
it was necessary because lines may have been tokenized multiple times.
*/
enum if_state CurrIfState;
static int blocknestlevel;
static int falseblocknestlevel;
static uint_32 elseoccured; /* 2.06: bit field, magnitude must be >= MAX_IF_NESTING */
#ifdef DEBUG_OUT
static const char *GetCurrIfStatString( void )
/********************************************/
{
switch ( CurrIfState ) {
case BLOCK_ACTIVE: return( "BLOCK_ACTIVE" );
case BLOCK_INACTIVE: return( "BLOCK_INACTIVE" );
default: return( "BLOCK_DONE" );
}
}
#endif
/*
* this code runs after the first token has been scanned,
* if it is a IFx, ELSEx or ENDIF.
* updates variables <blocknestlevel> and <falseblocknestlevel>.
*/
void conditional_assembly_prepare( int directive )
/************************************************/
{
DebugMsg1(("condasm_prepare(%s), old status: %s, lvl=%u, falselvl=%u\n",
GetResWName( directive, NULL), GetCurrIfStatString(), blocknestlevel, falseblocknestlevel));
switch( directive ) {
case T_IF:
case T_IF1:
case T_IF2:
case T_IFB:
case T_IFDEF:
case T_IFDIF:
case T_IFDIFI:
case T_IFE:
case T_IFIDN:
case T_IFIDNI:
case T_IFNB:
case T_IFNDEF:
if( CurrIfState != BLOCK_ACTIVE ) {
falseblocknestlevel++;
break;
}
if( blocknestlevel == MAX_IF_NESTING ) {
EmitError( NESTING_LEVEL_TOO_DEEP );
break;
}
elseoccured &= ~( 1 << blocknestlevel ); /* v2.06: added */
blocknestlevel++;
break;
case T_ELSE:
case T_ELSEIF:
case T_ELSEIF1:
case T_ELSEIF2:
case T_ELSEIFB:
case T_ELSEIFDEF:
case T_ELSEIFDIF:
case T_ELSEIFDIFI:
case T_ELSEIFE:
case T_ELSEIFIDN:
case T_ELSEIFIDNI:
case T_ELSEIFNB:
case T_ELSEIFNDEF:
if ( blocknestlevel ) { /* v2.04: do nothing if there was no IFx */
if ( falseblocknestlevel > 0 ) {
break;
}
/* v2.06: check added to detect multiple ELSE branches */
if ( elseoccured & ( 1 << ( blocknestlevel - 1 ) ) ) {
EmitError( ELSE_CLAUSE_ALREADY_OCCURED_IN_THIS_IF_BLOCK );
break;
}
/* status may change:
* inactive -> active
* active -> done
*/
CurrIfState = (( CurrIfState == BLOCK_INACTIVE ) ? BLOCK_ACTIVE : BLOCK_DONE );
/* v2.06: no further ELSEx once ELSE was detected */
if ( directive == T_ELSE )
elseoccured |= ( 1 << ( blocknestlevel - 1 ) );
} else {
EmitErr( BLOCK_NESTING_ERROR, GetResWName( directive, NULL ) );
}
break;
case T_ENDIF:
if ( blocknestlevel ) {
if ( falseblocknestlevel > 0 ) {
falseblocknestlevel--;
break;
}
blocknestlevel--;
CurrIfState = BLOCK_ACTIVE; /* v2.04: added */
} else {
EmitErr( BLOCK_NESTING_ERROR, GetResWName( directive, NULL ) );
}
break;
}
DebugMsg1(("condasm_prepare(%s), new status: %s, lvl=%u, falselvl=%u\n",
GetResWName( directive, NULL ), GetCurrIfStatString(), blocknestlevel, falseblocknestlevel));
return;
}
/* handle [ELSE]IF[N]DEF
* <string> is
* - the value of a T_ID item!
* - "" (item is T_FINAL)
*/
static bool check_defd( const char *name )
/****************************************/
{
struct asym *sym;
if ( *name ) {
sym = SymSearch( name );
if( sym ) {
DebugMsg1(("check_defd(%s): state=%u defined=%u\n", name, sym->state, sym->isdefined ));
/* v2.04: changed. the "defined" flag is active for ALL symbols */
//if ( sym->state == SYM_INTERNAL || sym->state == SYM_MACRO || sym->state == SYM_TMACRO || sym->state == SYM_UNDEFINED ) {
return( sym->isdefined );
}
DebugMsg1(("check_defd(%s): sym=NULL\n", name ));
}
return( FALSE );
}
/* handle [ELSE]IF[N]B
*/
static bool check_blank( const char *string )
/*******************************************/
{
for ( ;*string; string++ )
if ( isspace(*string) == FALSE )
return FALSE;
return( TRUE );
}
/* Are two strings different?
* Used by [ELSE]IFDIF[I] and [ELSE]IFIDN[I]
*/
static bool check_dif( const char *string1, const char *string2, bool sensitive )
/*******************************************************************************/
{
if( sensitive ) {
return( strcmp( string1, string2 ) != 0 );
} else {
return( _stricmp( string1, string2 ) != 0 );
}
}
ret_code CondAsmDirective( int i, struct asm_tok tokenarray[] )
/*************************************************************/
{
int directive = tokenarray[i].tokval;
const char *string1;
const char *string2;
enum if_state NextIfState;
struct expr opndx;
if ( CurrIfState != BLOCK_ACTIVE ) {
DebugMsg1(("CondAsmDirective(%s), CurrIfState=%u(%s), lvl=%u, falselvl=%u\n",
GetResWName(directive, NULL), CurrIfState, GetCurrIfStatString(), blocknestlevel, falseblocknestlevel));
if ( i || ModuleInfo.listif ) {
LstWriteSrcLine();
}
return( NOT_ERROR );
}
if ( ModuleInfo.list == TRUE ) {
if ( MacroLevel == 0 ||
ModuleInfo.list_macro == LM_LISTMACROALL ||
ModuleInfo.listif )
LstWriteSrcLine();
}
DebugMsg1(("CondAsmDirective(%s), BLOCK_ACTIVE, lvl=%u, falselvl=%u [%s]\n", GetResWName(directive, NULL), blocknestlevel, falseblocknestlevel, tokenarray[i].tokpos ));
i++; /* go past IFx, ELSEx, ENDIF */
/* check params and call appropriate test routine */
switch( GetSflagsSp(directive) ) {
case CC_NUMARG: /* [ELSE]IF[E] */
/* no forward reference allowed, symbol must be defined */
if ( ( ERROR == EvalOperand( &i, tokenarray, Token_Count, &opndx, EXPF_NOUNDEF ) ) ) {
DebugMsg(("CondAsmDirective(%s), EvalOperand returned with ERROR\n", GetResWName(directive, NULL) ));
/* v2.11: don't exit, assume 0 */
//return( ERROR );
opndx.kind = EXPR_CONST;
opndx.value = 0;
i = Token_Count;
}
#if 0 /* v2.05: obsolete */
if ( opndx.sym && opndx.sym->state == SYM_UNDEFINED ) {
EmitErr( SYMBOL_NOT_DEFINED, opndx.sym->name );
} else
#endif
if ( opndx.kind == EXPR_CONST )
;
else if ( opndx.kind == EXPR_ADDR && opndx.indirect == FALSE ) {
opndx.value += opndx.sym->offset;
/* v2.07: Masm doesn't accept a relocatable item,
* so emit at least a warning!
*/
EmitWarn( 2, CONSTANT_EXPECTED );
} else {
return( EmitError( CONSTANT_EXPECTED ) );
}
if ( directive == T_IF || directive == T_ELSEIF )
NextIfState = ( opndx.value ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
else
NextIfState = ( !opndx.value ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
break;
case CC_LITARG: /* [ELSE]IFDIF[I], [ELSE]IFIDN[I] */
string1 = tokenarray[i].string_ptr;
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
if ( tokenarray[i].token == T_ID && SymSearch( string1 ) == NULL )
EmitErr( SYMBOL_NOT_DEFINED, string1 );
else
EmitError( TEXT_ITEM_REQUIRED );
return( ERROR );
}
i++;
if ( tokenarray[i].token != T_COMMA ) {
return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) );
}
i++;
string2 = tokenarray[i].string_ptr;
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
if ( tokenarray[i].token == T_ID && SymSearch( string2 ) == NULL )
EmitErr( SYMBOL_NOT_DEFINED, string2 );
else
EmitError( TEXT_ITEM_REQUIRED );
return( ERROR );
}
i++;
DebugMsg1(("CondAsmDirective(%s), cmp >%s< and >%s<\n", GetResWName(directive, NULL), string1, string2 ));
switch ( directive ) {
case T_IFDIF:
case T_ELSEIFDIF:
NextIfState = check_dif( string1, string2, TRUE ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
break;
case T_IFDIFI:
case T_ELSEIFDIFI:
NextIfState = check_dif( string1, string2, FALSE ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
break;
case T_IFIDN:
case T_ELSEIFIDN:
NextIfState = !check_dif( string1, string2, TRUE ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
break;
default:
NextIfState = !check_dif( string1, string2, FALSE ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
}
break;
case CC_BLKARG: /* [ELSE]IF[N]B */
string1 = tokenarray[i].string_ptr;
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
if ( tokenarray[i].token == T_ID && SymSearch( string1 ) == NULL )
EmitErr( SYMBOL_NOT_DEFINED, string1 );
else
EmitError( TEXT_ITEM_REQUIRED );
return( ERROR );
}
i++;
if ( directive == T_IFB || directive == T_ELSEIFB ) {
NextIfState = check_blank( string1 ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
} else {
NextIfState = !check_blank( string1 ) ? BLOCK_ACTIVE : BLOCK_INACTIVE;
}
break;
case CC_PASS1: /* [ELSE]IF1 */
/* v2.04: changed */
//NextIfState = ((Parse_Pass == PASS_1) ? BLOCK_ACTIVE : BLOCK_INACTIVE);
NextIfState = BLOCK_ACTIVE;
break;
case CC_PASS2: /* [ELSE]IF2 */
if ( ModuleInfo.setif2 == FALSE ) {
EmitError( IF2_NOT_ALLOWED );
break;
}
/* v2.04: changed */
//NextIfState = ((Parse_Pass == PASS_1) ? BLOCK_INACTIVE : BLOCK_ACTIVE);
NextIfState = BLOCK_ACTIVE;
break;
case CC_SYMARG: /* [ELSE]IF[N]DEF */
NextIfState = BLOCK_INACTIVE;
/* Masm's implementation works with IDs as arguments only. The rest
* will return FALSE. However, it's nice to be able to check whether
* a reserved word is defined or not.
*/
/* v2.0: [ELSE]IF[N]DEF is valid *without* an argument! */
//if ( tokenarray[i].token == T_ID && tokenarray[i+1].token == T_FINAL) {
if ( tokenarray[i].token == T_FINAL ) {
} else if ( tokenarray[i].token == T_ID ) {
/* v2.07: handle structs + members (if -Zne is NOT set) */
struct asym *sym;
if ( Options.strict_masm_compat == FALSE &&
tokenarray[i+1].token == T_DOT &&
( sym = SymSearch( tokenarray[i].string_ptr ) ) &&
( ( sym->state == SYM_TYPE ) || sym->type ) ) {
uint_32 value;
value = 0;
do {
i += 2;
/* if it's a structured variable, use its type! */
if ( sym->state != SYM_TYPE )
sym = sym->type;
sym = SearchNameInStruct( sym, tokenarray[i].string_ptr, &value, 0 );
} while ( sym && tokenarray[i+1].token == T_DOT );
NextIfState = ( sym ? BLOCK_ACTIVE : BLOCK_INACTIVE );
} else {
NextIfState = ( check_defd( tokenarray[i].string_ptr ) ? BLOCK_ACTIVE : BLOCK_INACTIVE );
}
i++;
} else if ( tokenarray[i].token == T_RES_ID && tokenarray[i].tokval == T_FLAT ) {
/* v2.09: special treatment of FLAT added */
NextIfState = (( ModuleInfo.flat_grp && ModuleInfo.flat_grp->sym.isdefined ) ? BLOCK_ACTIVE : BLOCK_INACTIVE );
i++;
} else if ( Options.strict_masm_compat == FALSE && (
tokenarray[i].token == T_RES_ID ||
tokenarray[i].token == T_STYPE ||
tokenarray[i].token == T_INSTRUCTION ||
tokenarray[i].token == T_DIRECTIVE ||
//tokenarray[i].token == T_UNARY_OP ||
//tokenarray[i].token == T_BINARY_OP ||
tokenarray[i].token == T_REG ) &&
tokenarray[i+1].token == T_FINAL ) {
NextIfState = BLOCK_ACTIVE;
i++;
}
if ( tokenarray[i].token != T_FINAL ) {
EmitWarn( 2, IFDEF_EXPECTS_SYMBOL_ARGUMENT, tokenarray[i-1].tokpos );
while ( tokenarray[i].token != T_FINAL ) i++;
}
if ( directive == T_IFNDEF || directive == T_ELSEIFNDEF )
NextIfState = ( ( NextIfState == BLOCK_ACTIVE ) ? BLOCK_INACTIVE : BLOCK_ACTIVE );
break;
default: /* ELSE and ENDIF */
NextIfState = BLOCK_ACTIVE;
break;
}
if ( tokenarray[i].token != T_FINAL ) {
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
}
CurrIfState = NextIfState;
DebugMsg1(("CondAsmDirective(%s) exit, state=%s, lvl=%u, falselvl=%u\n",
GetResWName(directive, NULL), GetCurrIfStatString(), blocknestlevel, falseblocknestlevel));
return( NOT_ERROR );
}
static char * GetErrText( int i, struct asm_tok tokenarray[] )
/************************************************************/
{
*StringBufferEnd = NULLC;
if ( i ) {
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
TextItemError( &tokenarray[i] );
} else {
*(StringBufferEnd+0) = ':';
*(StringBufferEnd+1) = ' ';
//GetLiteralValue( buffer+2, text->string_ptr );
strcpy( StringBufferEnd+2, tokenarray[i].string_ptr );
}
}
return( StringBufferEnd );
}
/* v2.05: the error directives are no longer handled in the
* preprocessor, because the errors are displayed in pass 2 only
* - .err [<text>]
* - .err<1|2> [<text>]
* - .err<e|nz> expression [, <text>]
* - .errdif[i] literal1, literal2 [, <text>]
* - .erridn[i] literal1, literal2 [, <text>]
* - .err[n]b text_literal [, <text>]
* - .err[n]def symbol [, <text>]
*/
ret_code ErrorDirective( int i, struct asm_tok tokenarray[] )
/***********************************************************/
{
struct expr opndx;
unsigned direct;
const char *string1;
const char *string2;
int errmsg = EMPTY;
int erridx = 0;
struct asym *sym;
int idloc;
direct = tokenarray[i].tokval;
i++; /* go past directive */
/* get an expression if necessary */
switch( GetSflagsSp( direct) ) {
case CC_NUMARG: /* .ERR[E|NZ] */
if (( ERROR == EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) ))
return( ERROR );
if ( opndx.kind == EXPR_CONST )
;
else if ( opndx.kind == EXPR_ADDR && opndx.indirect == FALSE && opndx.sym && opndx.sym->state == SYM_UNDEFINED )
;//opndx.value += opndx.sym->offset;
else {
return( EmitError( CONSTANT_EXPECTED ) );
}
if ( tokenarray[i].token == T_COMMA && tokenarray[i+1].token != T_FINAL ) {
i++;
erridx = i++;
}
if ( Parse_Pass == PASS_1 )
break;
if ( direct == T_DOT_ERRNZ && opndx.value ) {
errmsg = FORCED_NOT_ZERO;
} else if ( direct == T_DOT_ERRE && !opndx.value ) {
errmsg = FORCED_EQUAL;
}
if ( errmsg != EMPTY )
EmitErr( errmsg, opndx.value, GetErrText( erridx, tokenarray ) );
break;
case CC_SYMARG: /* .ERR[N]DEF */
/* there's a special handling of these directives in ExpandLine()! */
if ( tokenarray[i].token != T_ID ) {
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
}
idloc = i;
/* skip the next param */
do {
i++;
} while ( tokenarray[i].token == T_DOT || tokenarray[i].token == T_ID );
if ( tokenarray[i].token == T_COMMA && tokenarray[i+1].token != T_FINAL ) {
/* v2.05: added */
/* v2.08: obsolete, the expansion occurs in the preprocessor.
* See ExpandLine() in expans.c
*/
//ExpandLineItems( tokenarray[i].tokpos, i, tokenarray, TRUE, FALSE );
i++;
erridx = i++; /* Masm seems to accept anything as text */
}
//if ( tokenarray[i].token != T_FINAL )
// break;
/* should run on pass 2 only! */
if ( Parse_Pass == PASS_1 )
break;
/* don't use check_defd()! */
/* v2.07: check for structured variables */
if ( Options.strict_masm_compat == FALSE &&
tokenarray[idloc+1].token == T_DOT &&
( sym = SymSearch( tokenarray[idloc].string_ptr ) ) &&
( ( sym->state == SYM_TYPE ) || sym->type ) ) {
uint_32 value;
int j = idloc;
int size;
value = 0;
do {
j += 2;
/* if it's a structured variable, use its type! */
if ( sym->state != SYM_TYPE )
sym = sym->type;
sym = SearchNameInStruct( sym, tokenarray[j].string_ptr, &value, 0 );
} while ( sym && tokenarray[j+1].token == T_DOT );
if ( tokenarray[j].token == T_ID )
j++;
else if ( tokenarray[j].token != T_FINAL && tokenarray[j].token != T_COMMA ) {
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[j].string_ptr ) );
}
size = tokenarray[j].tokpos - tokenarray[idloc].tokpos;
memcpy( StringBufferEnd, tokenarray[idloc].tokpos, size );
*(StringBufferEnd+size) = NULLC;
} else {
sym = SymSearch( tokenarray[idloc].string_ptr );
strcpy( StringBufferEnd, tokenarray[idloc].string_ptr );
}
if ( sym && sym->state == SYM_UNDEFINED )
sym = NULL;
/* Masm "usually" ignores the optional errtxt! */
if( erridx ) {
strcat( StringBufferEnd, " : " );
strcat( StringBufferEnd, tokenarray[erridx].string_ptr );
}
if( direct == T_DOT_ERRDEF && sym != NULL )
EmitErr( FORCED_DEF, StringBufferEnd );
else if( direct == T_DOT_ERRNDEF && sym == NULL )
EmitErr( FORCED_NOT_DEF, StringBufferEnd );
break;
case CC_BLKARG: /* .ERR[N]B */
string1 = tokenarray[i].string_ptr;
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
return( TextItemError( &tokenarray[i] ) );
}
i++;
if ( tokenarray[i].token == T_COMMA && tokenarray[i+1].token != T_FINAL ) {
i++;
erridx = i++;
}
if ( Parse_Pass == PASS_1 )
break;
if ( direct == T_DOT_ERRB && check_blank( string1 ) )
errmsg = FORCED_BLANK;
else if ( direct == T_DOT_ERRNB && !check_blank( string1 ) )
errmsg = FORCED_NOT_BLANK;
if ( errmsg != EMPTY )
EmitErr( errmsg, string1, GetErrText( erridx, tokenarray ) );
break;
case CC_LITARG: /* .ERRDIF[I], .ERRIDN[I] */
string1 = tokenarray[i].string_ptr;
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
return( TextItemError( &tokenarray[i] ) );
}
i++;
if ( tokenarray[i].token != T_COMMA ) {
return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) );
}
i++;
string2 = tokenarray[i].string_ptr;
if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) {
return( TextItemError( &tokenarray[i] ) );
}
i++;
if ( tokenarray[i].token == T_COMMA && tokenarray[i+1].token != T_FINAL ) {
i++;
erridx = i++;
}
if ( Parse_Pass == PASS_1 )
break;
switch ( direct ) {
case T_DOT_ERRDIF:
if ( check_dif( string1, string2, TRUE ) )
errmsg = FORCED_DIF;
break;
case T_DOT_ERRDIFI:
if ( check_dif( string1, string2, FALSE ) )
errmsg = FORCED_DIF;
break;
case T_DOT_ERRIDN:
if ( !check_dif( string1, string2, TRUE ) )
errmsg = FORCED_IDN;
break;
default:
if ( !check_dif( string1, string2, FALSE ) )
errmsg = FORCED_IDN;
}
if ( errmsg != EMPTY )
EmitErr( errmsg, string1, string2, GetErrText( erridx, tokenarray ) );
break;
case CC_PASS2: /* .ERR2 */
if ( ModuleInfo.setif2 == FALSE ) {
return( EmitError( IF2_NOT_ALLOWED ) );
}
case CC_PASS1: /* .ERR1 */
default: /* .ERR */
if ( tokenarray[i].token != T_FINAL ) {
erridx = i++;
}
if ( Parse_Pass == PASS_1 )
break;
EmitErr( FORCED_ERR, GetErrText( erridx, tokenarray ) );
break;
}
if ( tokenarray[i].token != T_FINAL ) {
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) );
}
return( NOT_ERROR );
}
void CondCheckOpen( void )
/************************/
{
if( blocknestlevel > 0 ) {
EmitErr( BLOCK_NESTING_ERROR, "if-else" );
}
return;
}
int GetIfNestLevel( void )
/************************/
{
return( blocknestlevel );
}
void SetIfNestLevel( int newlevel )
/*********************************/
{
blocknestlevel = newlevel;
return;
}
/* init (called once per module) */
void CondInit( void )
/*******************/
{
CurrIfState = BLOCK_ACTIVE;
blocknestlevel = 0;
falseblocknestlevel = 0;
}