office-gobmx/dmake/macparse.c
Ivo Hinkelmann 551eb4d6c3 INTEGRATION: CWS dmake411 (1.2.16); FILE MERGED
2007/08/09 19:46:38 vq 1.2.16.3:
#i69510# Change error on assignment to an empty macro name to a warning.
2007/08/08 16:54:59 vq 1.2.16.2: #i69510# Improve error message.
2007/08/08 16:52:21 vq 1.2.16.1: #i69510# Improve macro name syntax check during assignment.
2007-10-15 14:40:02 +00:00

232 lines
5.7 KiB
C

/* RCS $Id: macparse.c,v 1.3 2007-10-15 15:40:02 ihi Exp $
--
-- SYNOPSIS
-- Parse a macro definition
--
-- DESCRIPTION
-- This file contains the code that parses a macro definition
-- stored in a buffer. If the string in buffer is not a valid
-- macro definition the routie Parse_macro returns 0, otherwise it
-- returns 1 to indicate success.
--
-- AUTHOR
-- Dennis Vadura, dvadura@dmake.wticorp.com
--
-- WWW
-- http://dmake.wticorp.com/
--
-- COPYRIGHT
-- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
--
-- This program is NOT free software; you can redistribute it and/or
-- modify it under the terms of the Software License Agreement Provided
-- in the file <distribution-root>/readme/license.txt.
--
-- LOG
-- Use cvs log to obtain detailed change logs.
*/
#include "extern.h"
PUBLIC int
Parse_macro( buffer, flag )/*
=============================
Parse the string in buffer and define it as a macro if it is a valid macro.
Note especially the string .SETDIR= since it is an attribute, but looks a
lot like a macro definition. This would not be a problem if make used
white space as token separators, since this is not the case we must do
something about it. */
char *buffer;
int flag;
{
char *result; /* temporary pointer for strings */
TKSTR input; /* place to scan the buffer from */
HASHPTR hv; /* pointer to hash table value */
int operator; /* what macro operator do we have */
char *tok1; /* temporary place to keep a token */
char *tok2; /* temporary place to keep a token */
int toklen; /* length of a token */
DB_ENTER( "Parse_macro" );
SET_TOKEN( &input, buffer );
tok1 = Get_token( &input, "=+:*!?", 0 );
operator=Macro_op(tok1);
if( operator ) {
CLEAR_TOKEN( &input );
Error( "Assignment without macro name: [%s].", buffer );
DB_RETURN( 1 );
}
tok1 = DmStrDup(tok1);
tok2 = Get_token( &input, "=+:*!?", 2 );
if( !(operator = Macro_op(tok2)) || !strcmp(tok1,".SETDIR") ) {
CLEAR_TOKEN( &input );
FREE(tok1);
DB_RETURN(0);
}
tok2 = Expand(tok1); FREE(tok1); tok1 = tok2;
if ( !(toklen = strlen(tok1)) ) {
Warning( "Empty macro name after expansion: [%s].", buffer );
}
/* Catch illegal single character macro names. */
if ( toklen == 1 && strchr("{()}", tok1[0]) ) {
CLEAR_TOKEN( &input );
Fatal( "Syntax error in macro assignment [%s]. The following characters cannot be used as single letter macro names: '{()}'.", buffer );
}
/* Catch ':' in macro names. */
if ( strchr(tok1, ':') ) {
CLEAR_TOKEN( &input );
Fatal( "Syntax error in macro assignment [%s]. The character ':' is not allowed in macro names.", buffer );
}
tok2 = Get_token(&input, NIL( char ), FALSE);
/* Make sure we can force the assignment. */
if ( operator & M_OP_SI ) {
flag |= M_FORCE|M_MULTI;
operator &= ~M_OP_SI;
}
switch( operator ) {
case M_OP_PLCL:
tok2 = Expand( tok2 );
/* Fall thru */
case M_OP_PL:
/* Add to an existing macro, if it is not defined, though, then
* just define a new macro */
if( (hv = GET_MACRO(tok1)) == NIL(HASH) || hv->ht_value == NIL(char) )
Def_macro( tok1, tok2, flag );
else {
result = DmStrAdd( hv->ht_value, tok2, FALSE );
Def_macro( tok1, result, flag );
FREE( result );
}
if( operator == M_OP_PLCL ) FREE(tok2);
break;
case M_OP_DF:
/* *= */
/* internal default macros or initialized empty macros set M_INIT. */
if( (hv = GET_MACRO(tok1)) != NIL(HASH) && !(hv->ht_flag & M_INIT) )
break;
/* else FALLTHRU */
case M_OP_EQ:
Def_macro( tok1, tok2, flag );
break;
case M_OP_DFCL:
/* *:= */
/* internal default macros or initialized empty macros set M_INIT. */
if( (hv = GET_MACRO(tok1)) != NIL(HASH) && !(hv->ht_flag & M_INIT) )
break;
/* else FALLTHRU */
case M_OP_CL:
tok2 = Expand( tok2 );
Def_macro( tok1, tok2, M_EXPANDED | flag );
FREE( tok2 );
break;
case M_OP_CM:{
CELLPTR cp;
STRINGPTR sp;
if (flag & M_PUSH) {
Error("Nested conditional definition [%s ?= %s] ignored",
tok1, tok2);
}
else {
cp = Def_cell(tok1);
if (cp->ce_flag & F_MULTI) {
LINKPTR lp;
for(lp=cp->ce_prq; lp->cl_next; lp=lp->cl_next);
cp = lp->cl_prq;
}
TALLOC(sp,1,STRING);
sp->st_string = DmStrDup(tok2);
sp->st_next = cp->ce_cond;
cp->ce_cond = sp;
tok1 = NIL(char);
}
}
break;
}
if (tok1) {
if ( LastMacName != NIL(char) )
FREE( LastMacName );
LastMacName = tok1;
}
DB_RETURN( 1 );
}
PUBLIC int
Macro_op( op )/*
================
Check the passed in op string and map it to one of the macro operators */
char *op;
{
int ret = 0;
DB_ENTER( "macro_op" );
if ( *op == '!' ) {
ret = M_OP_SI;
op++;
}
switch( *op ) {
case '=': ret |= M_OP_EQ; break;
case ':': ret |= M_OP_CL; op++; break;
case '+':
op++;
if( *op == ':' ) {
ret |= M_OP_PLCL;
op++;
}
else {
ret |= M_OP_PL;
}
break;
case '*':
op++;
if( *op == ':' ) {
ret |= M_OP_DFCL;
op++;
}
else {
ret |= M_OP_DF;
}
break;
case '?':
ret |= M_OP_CM;
op++;
break;
}
if( *op != '=' )
ret = 0;
else {
op++;
if( *op != '\0' )
ret = 0;
}
DB_RETURN( ret );
}