macro.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 681 行 · 第 1/2 页
C
681 行
/****************************************************************************
*
* 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: maro processing routines
*
****************************************************************************/
#define PLACEHOLDER_SIZE 3 /* for #dd - number sign, digit, digit */
#include "asmglob.h"
#include <ctype.h>
#include "asmalloc.h"
#include "asmins.h"
#include "asmdefs.h"
#include "asmeval.h"
#include "asmexpnd.h"
#include "directiv.h"
#include "asminput.h"
#include "myassert.h"
extern bool GetQueueMacroHidden( void );
extern int_8 DefineProc; // TRUE if the definition of procedure
// has not ended
extern int MacroLocalVarCounter;
int MacroExitState = 0;
/* quick explanation:
*
* there are 2 entry points into this module:
* MacroDef & ExpandMacro
* MacroDef is called by asmins.c to define a macro
* ExpandMacro is called by asmline to check if something is a macro, and
* expand it if that is the case
*/
static asmlines *asmline_insert( asmlines **head, void *data )
/************************************************************/
{
asmlines *entry;
asmlines **ptr;
/* get a pointer to the last next ptr ( or Head if empty ) */
for( ptr = head; *ptr; ptr = &((*ptr)->next) );
entry = AsmAlloc( sizeof( asmlines ) );
entry->next = NULL;
entry->line = AsmAlloc( strlen( data ) + 1 );
entry->parmcount = 0;
strcpy( entry->line, data );
*ptr = entry;
return( entry );
}
static char *replace_parm( parm_list *parms, char *start, char len, asmlines *lstruct )
/*************************************************************************************/
{
/* search through parm list for word pointed at by start,
* if you find it, set up the line string
* this is similar to a printf format string
* the placeholders are of the form #dd ( #, digit, digit )
* this allows up to 100 parameters - lots :)
* fixme - this max. should be docmented & checked for.
*/
char buffer[10];
parm_list *p;
char *new_line;
char *old_line;
char before; // length of text before placeholder
char count = 0;
old_line = lstruct->line;
for( p = parms; p != NULL; p = p->next ) {
if( ( p->label != NULL ) && ( strlen( p->label ) == len ) &&
( strncmp( start, p->label, len ) == 0 ) ) {
/* hey! it matches! */
new_line = AsmAlloc( strlen(old_line) - len + PLACEHOLDER_SIZE +1 );
before = start - old_line;
if( *(start-1) == '&' ) before--;
strncpy( new_line, old_line, before );
*(new_line+before) = '\0';
strcat( new_line, "#" );
if( sprintf(buffer,"%2d", count ) != 2 ) {
myassert( 0 );
}
if( buffer[0] == ' ' ) buffer[0]='0'; /* no spaces */
strcat( new_line, buffer );
if( *(start+len) == '&' ) len++;
strcat( new_line, start+len );
lstruct->line = new_line;
lstruct->parmcount++;
AsmFree( old_line );
return( new_line + before + PLACEHOLDER_SIZE ); /* ptr to char after #dd */
}
count++;
}
return( start+len );
}
#define is_valid_id_char( ch ) \
( isalpha(ch) || isdigit(ch) || ch=='_' || ch=='@' || ch=='$' || ch=='?' )
static void put_parm_placeholders_in_line( asmlines *linestruct, parm_list *parms )
/*********************************************************************************/
{
char *line;
char *tmp;
char *start;
char quote = FALSE;
char len;
/* handle the substitution operator ( & ) */
line = linestruct->line;
for( tmp = line; *tmp != '\0'; ) {
/* scan across the string for space, &, " - to start a word */
line = tmp;
for( ; *tmp != '\0'; tmp++ ) {
if( is_valid_id_char( *tmp ) ) {
if( tmp == line ) break; /* ok to start at beginning of line */
continue;
} else if( isspace( *tmp ) ) {
/* find 1st non blank char */
while( isspace( *tmp ) ) tmp++;
break;
} else if( *tmp == '"' ) {
/* toggle the quote flag */
quote = ( quote + 1 ) %2;
tmp++;
break;
} else {
/* some other garbage */
tmp++;
break;
}
}
start = tmp;
/* scan across the string for space, &, " - to end the word */
for( ; *tmp != '\0'; tmp++ ) {
if( is_valid_id_char( *tmp ) ) {
continue;
} else if( isspace( *tmp ) ) {
break;
} else if( *tmp == '"' ) {
/* toggle the quote flag */
quote = ( quote + 1 ) %2;
break;
} else {
break;
}
}
len = tmp - start;
/* look for this word in the macro parms, and replace it if it is */
/* this would change line - it will have to be reallocated */
if( !quote || *start =='&' || *(start-1)=='&' || *(start+len+1)=='&' ) {
if( *start != '\0' && len > 0 ) {
tmp = replace_parm( parms, start, len, linestruct );
}
}
}
}
static int_8 lineis( char *str, char *substr )
/********************************************/
{
int len;
len = strlen( substr );
wipe_space( str );
if( strnicmp( str, substr, len ) ) {
return( FALSE );
}
if( str[len] != '\0' && !isspace( str[len] ) ) {
return( FALSE );
}
return( TRUE );
}
static int macro_local( void )
/****************************/
{
/* take a line that looks like LOCAL varname [, varname * ] */
int i = 0;
char buffer[MAX_LINE_LEN];
if( AsmBuffer[i]->value != T_LOCAL ) {
AsmError( SYNTAX_ERROR );
return( ERROR );
}
PushLineQueue();
for( i++; AsmBuffer[i]->token != T_FINAL; i++ ) {
/* define an equ to expand the specified variable to a temp. name */
if( AsmBuffer[i]->token != T_ID ) {
AsmError( OPERAND_EXPECTED );
return( ERROR );
}
strcpy( buffer, AsmBuffer[i]->string_ptr );
strcat( buffer, " TEXTEQU " );
sprintf( buffer + strlen( buffer ), "??%#04d", MacroLocalVarCounter );
MacroLocalVarCounter++;
InputQueueLine( buffer );
i++;
if( AsmBuffer[i]->token == T_FINAL ) break;
/* now skip the comma */
if( AsmBuffer[i]->token != T_COMMA ) {
AsmError( EXPECTING_COMMA );
return( ERROR );
}
}
return( NOT_ERROR );
}
static int macro_exam( int i )
/****************************/
{
macro_info *info;
char *string;
char *token;
char *name;
parm_list *paranode;
parm_list *paracurr;
asmlines *linestruct;
char buffer[ MAX_LINE_LEN ];
dir_node *dir;
uint nesting_depth = 0;
bool store_data;
name = AsmBuffer[i++]->string_ptr;
dir = (dir_node *)AsmGetSymbol( name );
info = dir->e.macroinfo;
store_data = Parse_Pass == PASS_1 || info->data == NULL;
/* go past "MACRO" */
i++;
if( store_data ) {
for( ; i < Token_Count ; ) {
token = AsmBuffer[i]->string_ptr;
paranode = AsmAlloc( sizeof( parm_list ) );
paranode->def = NULL;
paranode->replace = NULL;
paranode->required = FALSE;
/* first get the parm. name */
paranode->label = AsmAlloc( strlen( token ) + 1 );
strcpy( paranode->label, token );
i++;
/* now see if it has a default value or is required */
if( AsmBuffer[i]->token == T_COLON ) {
i++;
if( *AsmBuffer[i]->string_ptr == '=' ) {
i++;
if( AsmBuffer[i]->token != T_STRING ) {
AsmError( SYNTAX_ERROR );
return( ERROR );
}
token = AsmBuffer[i]->string_ptr;
paranode->def = AsmAlloc( strlen( token ) + 1 );
strcpy( paranode->def, token );
i++;
} else if( strcmp( AsmBuffer[i]->string_ptr, "REQ" ) == 0 ) {
/* required parameter */
paranode->required = TRUE;
i++;
}
}
if( i< Token_Count && AsmBuffer[i]->token != T_COMMA ) {
AsmError( EXPECTING_COMMA );
return( ERROR );
}
/* go past comma */
i++;
/* add this parm node to the list */
// fixme
paranode->next = NULL;
if( info->parmlist == NULL ) {
info->parmlist = paranode;
} else {
for( paracurr = info->parmlist;; paracurr = paracurr->next ) {
if( paracurr->next == NULL ) break;
}
paracurr->next = paranode;
}
} /* looping through parameters */
}
/* now read in all the contents of the macro, and store them */
for( ; ; ) {
char *ptr;
string = ReadTextLine( buffer );
if( string == NULL ) {
AsmError( UNEXPECTED_END_OF_FILE );
return( ERROR );
} else if( lineis( string, "endm" ) ) {
if( nesting_depth ) {
nesting_depth--;
} else {
return( NOT_ERROR );
}
}
ptr = string;
while( isspace( *ptr ) ) ptr++;
if( lineis( ptr, "for" )
|| lineis( ptr, "forc" )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?