2012-02-05 11:35:58 -05:00
|
|
|
/****************************************************************
|
|
|
|
* *
|
|
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
|
|
* *
|
|
|
|
* This source code contains the intellectual property *
|
|
|
|
* of its copyright holder(s), and is made available *
|
|
|
|
* under a license. If you do not know the terms of *
|
|
|
|
* the license, please stop and do not read further. *
|
|
|
|
* *
|
|
|
|
****************************************************************/
|
|
|
|
|
|
|
|
#include "mdef.h"
|
|
|
|
|
|
|
|
#include "gtm_string.h"
|
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "toktyp.h"
|
|
|
|
#include "stringpool.h"
|
|
|
|
#include "gtm_caseconv.h"
|
|
|
|
#include "advancewindow.h"
|
|
|
|
#include "show_source_line.h"
|
|
|
|
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
|
|
#include "gtm_utf8.h"
|
|
|
|
#include "gtm_icu_api.h" /* U_ISPRINT() needs this header */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
GBLREF unsigned char *source_buffer;
|
|
|
|
GBLREF short int source_column;
|
|
|
|
GBLREF char *lexical_ptr;
|
|
|
|
GBLREF spdesc stringpool;
|
|
|
|
GBLREF boolean_t gtm_utf8_mode;
|
|
|
|
GBLREF boolean_t run_time;
|
|
|
|
|
|
|
|
LITREF char ctypetab[NUM_CHARS];
|
|
|
|
|
|
|
|
error_def(ERR_LITNONGRAPH);
|
2012-03-24 14:06:46 -04:00
|
|
|
error_def(ERR_NUMOFLOW);
|
2012-02-05 11:35:58 -05:00
|
|
|
|
|
|
|
static readonly unsigned char apos_ok[] =
|
|
|
|
{
|
|
|
|
0,TK_NEXCLAIMATION,0,0,0,0,TK_NAMPERSAND,0
|
|
|
|
,0,0,0,0,0,0,0,0
|
|
|
|
,0,0,0,0,0,0,0,0
|
|
|
|
,0,0,0,0,TK_NLESS,TK_NEQUAL,TK_NGREATER,TK_NQUESTION
|
|
|
|
,0,0,0,0,0,0,0,0
|
|
|
|
,0,0,0,0,0,0,0,0
|
|
|
|
,0,0,0,0,0,0,0,0
|
|
|
|
,0,0,0,TK_NLBRACKET,0,TK_NRBRACKET,0,0
|
|
|
|
};
|
|
|
|
|
|
|
|
void advancewindow(void)
|
|
|
|
{
|
|
|
|
unsigned char *cp1, *cp2, *cp3, x;
|
|
|
|
char *tmp, source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
|
|
|
|
int y, charlen;
|
|
|
|
# ifdef UNICODE_SUPPORTED
|
|
|
|
uint4 ch;
|
|
|
|
unsigned char *cptr;
|
|
|
|
# endif
|
|
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
|
|
TREF(last_source_column) = source_column;
|
|
|
|
source_column = (unsigned char *)lexical_ptr - source_buffer + 1;
|
2012-03-24 14:06:46 -04:00
|
|
|
TREF(window_token) = TREF(director_token);
|
|
|
|
TREF(window_mval) = TREF(director_mval);
|
|
|
|
(TREF(director_mval)).mvtype = 0; /* keeps mval from being GC'd since it is not useful until re-used */
|
|
|
|
tmp = (TREF(window_ident)).addr; /* More efficient to swap pointers between window_ident.addr & director_ident.addr */
|
|
|
|
TREF(window_ident) = TREF(director_ident); /* than to copy text from director_ident to window_ident */
|
|
|
|
(TREF(director_ident)).addr = tmp;
|
2012-02-05 11:35:58 -05:00
|
|
|
x = *lexical_ptr;
|
|
|
|
switch (y = ctypetab[x])
|
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
case TK_EOL:
|
|
|
|
TREF(director_token) = TK_EOL;
|
|
|
|
return; /* if next character is terminator, avoid incrementing past it */
|
|
|
|
case TK_QUOTE:
|
|
|
|
ENSURE_STP_FREE_SPACE(MAX_SRCLINE);
|
|
|
|
cp1 = (unsigned char *)lexical_ptr + 1;
|
|
|
|
cp2 = cp3 = stringpool.free;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
# ifdef UNICODE_SUPPORTED
|
|
|
|
if (gtm_utf8_mode)
|
|
|
|
cptr = (unsigned char *)UTF8_MBTOWC((sm_uc_ptr_t)cp1, source_buffer + MAX_SRCLINE, ch);
|
|
|
|
# endif
|
|
|
|
x = *cp1++;
|
|
|
|
if ((SP > x) UNICODE_ONLY(|| (gtm_utf8_mode && !(U_ISPRINT(ch)))))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
TREF(last_source_column) = cp1 - source_buffer;
|
|
|
|
if ('\0' == x)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
TREF(director_token) = TREF(window_token) = TK_ERROR;
|
|
|
|
return;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
if (!run_time)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
|
|
|
|
dec_err(VARLSTCNT(1) ERR_LITNONGRAPH);
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
if ('\"' == x)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
UNICODE_ONLY(assert(!gtm_utf8_mode || (cp1 == cptr)));
|
|
|
|
if ('\"' == *cp1)
|
|
|
|
cp1++;
|
|
|
|
else
|
2012-02-05 11:35:58 -05:00
|
|
|
break;
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
*cp2++ = x;
|
|
|
|
# ifdef UNICODE_SUPPORTED
|
|
|
|
if (gtm_utf8_mode && (cptr > cp1))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
assert(4 > (cptr - cp1));
|
|
|
|
for (; cptr > cp1;)
|
|
|
|
*cp2++ = *cp1++;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
# endif
|
|
|
|
assert(cp2 <= stringpool.top);
|
|
|
|
}
|
|
|
|
lexical_ptr = (char *)cp1;
|
|
|
|
TREF(director_token) = TK_STRLIT;
|
|
|
|
(TREF(director_mval)).mvtype = MV_STR;
|
|
|
|
(TREF(director_mval)).str.addr = (char *)cp3;
|
|
|
|
(TREF(director_mval)).str.len = INTCAST(cp2 - cp3);
|
|
|
|
stringpool.free = cp2;
|
|
|
|
s2n(&(TREF(director_mval)));
|
|
|
|
# ifdef UNICODE_SUPPORTED
|
|
|
|
if (gtm_utf8_mode && !run_time)
|
|
|
|
{ /* UTF8 mode and not compiling an indirect gets an optimization to set the
|
|
|
|
* (true) length of the string into the mval
|
|
|
|
*/
|
|
|
|
charlen = utf8_len_stx(&(TREF(director_mval)).str);
|
|
|
|
if (0 > charlen) /* got a BADCHAR error */
|
|
|
|
TREF(director_token) = TK_ERROR;
|
|
|
|
else
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
assert(charlen == (TREF(director_mval)).str.char_len);
|
|
|
|
(TREF(director_mval)).mvtype |= MV_UTF_LEN;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
}
|
|
|
|
# endif
|
|
|
|
return;
|
|
|
|
case TK_LOWER:
|
|
|
|
case TK_PERCENT:
|
|
|
|
case TK_UPPER:
|
|
|
|
cp2 = (unsigned char *)((TREF(director_ident)).addr);
|
|
|
|
cp3 = cp2 + MAX_MIDENT_LEN;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (cp2 < cp3)
|
|
|
|
*cp2++ = x;
|
|
|
|
y = ctypetab[x = *++lexical_ptr];
|
|
|
|
if ((TK_UPPER != y) && (TK_DIGIT != y) && (TK_LOWER != y))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
(TREF(director_ident)).len = INTCAST(cp2 - (unsigned char*)(TREF(director_ident)).addr);
|
|
|
|
TREF(director_token) = TK_IDENT;
|
|
|
|
return;
|
|
|
|
case TK_PERIOD:
|
|
|
|
if (ctypetab[x = *(lexical_ptr + 1)] != TK_DIGIT)
|
|
|
|
break;
|
|
|
|
case TK_DIGIT:
|
|
|
|
(TREF(director_mval)).str.addr = lexical_ptr;
|
|
|
|
(TREF(director_mval)).str.len = MAX_SRCLINE;
|
|
|
|
(TREF(director_mval)).mvtype = MV_STR;
|
|
|
|
lexical_ptr = (char *)s2n(&(TREF(director_mval)));
|
|
|
|
if (!((TREF(director_mval)).mvtype &= MV_NUM_MASK))
|
|
|
|
{
|
|
|
|
stx_error(ERR_NUMOFLOW);
|
|
|
|
TREF(director_token) = TK_ERROR;
|
2012-02-05 11:35:58 -05:00
|
|
|
return;
|
2012-03-24 14:06:46 -04:00
|
|
|
}
|
|
|
|
if (TREF(s2n_intlit))
|
|
|
|
{
|
|
|
|
TREF(director_token) = TK_NUMLIT ;
|
|
|
|
n2s(&(TREF(director_mval)));
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
TREF(director_token) = TK_INTLIT ;
|
|
|
|
(TREF(director_mval)).str.len = INTCAST(lexical_ptr - (TREF(director_mval)).str.addr);
|
|
|
|
ENSURE_STP_FREE_SPACE((TREF(director_mval)).str.len);
|
|
|
|
memcpy(stringpool.free, (TREF(director_mval)).str.addr, (TREF(director_mval)).str.len);
|
|
|
|
assert (stringpool.free <= stringpool.top) ;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case TK_APOSTROPHE:
|
|
|
|
if (( x = *++lexical_ptr) >= 32)
|
|
|
|
{
|
|
|
|
x -= 32;
|
|
|
|
if (x < SIZEOF(apos_ok) / SIZEOF(unsigned char))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
if (y = apos_ok[x])
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
if (DEL < (x = *++lexical_ptr))
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-03-24 14:06:46 -04:00
|
|
|
TREF(director_token) = TK_ERROR;
|
2012-02-05 11:35:58 -05:00
|
|
|
return;
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
if (TK_RBRACKET == ctypetab[x])
|
|
|
|
{
|
|
|
|
lexical_ptr++;
|
|
|
|
y = TK_NSORTS_AFTER;
|
|
|
|
}
|
|
|
|
TREF(director_token) = y;
|
|
|
|
return;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
}
|
|
|
|
TREF(director_token) = TK_APOSTROPHE;
|
|
|
|
return;
|
|
|
|
case TK_SEMICOLON:
|
|
|
|
while (*++lexical_ptr)
|
2012-02-05 11:35:58 -05:00
|
|
|
;
|
2012-03-24 14:06:46 -04:00
|
|
|
assert(TK_EOL == ctypetab[*lexical_ptr]);
|
|
|
|
TREF(director_token) = TK_EOL;
|
|
|
|
return; /* if next character is terminator, avoid incrementing past it */
|
|
|
|
case TK_ASTERISK:
|
|
|
|
if (DEL < (x = *(lexical_ptr + 1)))
|
|
|
|
{
|
|
|
|
TREF(director_token) = TK_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (TK_ASTERISK == ctypetab[x])
|
|
|
|
{
|
|
|
|
lexical_ptr++;
|
|
|
|
y = TK_EXPONENT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TK_RBRACKET:
|
|
|
|
if ((x = *(lexical_ptr + 1)) > DEL)
|
|
|
|
{
|
|
|
|
TREF(director_token) = TK_ERROR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (TK_RBRACKET == ctypetab[x])
|
|
|
|
{
|
|
|
|
lexical_ptr++;
|
|
|
|
y = TK_SORTS_AFTER;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
lexical_ptr++;
|
2012-03-24 14:06:46 -04:00
|
|
|
TREF(director_token) = y;
|
2012-02-05 11:35:58 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GTM_TRIGGER
|
|
|
|
/* The M standard does not allow the '#' character to appear inside mnames but in specific places, we want to allow this
|
|
|
|
* so that triggers, which have the imbedded '#' character in their routine names, can be debugged and printed. The places
|
|
|
|
* where this is allowed follow.
|
|
|
|
*
|
|
|
|
* 1. $TEXT()
|
|
|
|
* 2. ZBREAK
|
|
|
|
* 3. ZPRINT
|
|
|
|
*
|
|
|
|
* All other uses still prohibit '#' from being in an MNAME. Routines that need to allow # in a name can call this routine to
|
|
|
|
* recombine the existing token and the look-ahead (director) token such that '#' is considered part of an mident.
|
|
|
|
*/
|
|
|
|
void advwindw_hash_in_mname_allowed(void)
|
|
|
|
{
|
|
|
|
unsigned char *cp2, *cp3, x;
|
|
|
|
unsigned char ident_buffer[SIZEOF(mident_fixed)];
|
|
|
|
int ident_len, ch;
|
2012-03-24 14:06:46 -04:00
|
|
|
DCL_THREADGBL_ACCESS;
|
2012-02-05 11:35:58 -05:00
|
|
|
|
2012-03-24 14:06:46 -04:00
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
|
|
assert(TK_IDENT == TREF(window_token));
|
|
|
|
assert(TK_HASH == TREF(director_token));
|
2012-02-05 11:35:58 -05:00
|
|
|
/* First copy the existing token we want to expand into our safe-haven */
|
2012-03-24 14:06:46 -04:00
|
|
|
memcpy(ident_buffer, (TREF(window_ident)).addr, (TREF(window_ident)).len);
|
2012-02-05 11:35:58 -05:00
|
|
|
/* Now parse further until we run out of [m]ident */
|
2012-03-24 14:06:46 -04:00
|
|
|
cp2 = ident_buffer + (TREF(window_ident)).len;
|
2012-02-05 11:35:58 -05:00
|
|
|
cp3 = ident_buffer + MAX_MIDENT_LEN;
|
|
|
|
*cp2++ = '#'; /* We are only called if director token is '#' so put that char in buffer now */
|
|
|
|
/* Start processing with the token following the '#' */
|
|
|
|
for (x = *lexical_ptr, ch = ctypetab[x];
|
|
|
|
((TK_UPPER == ch) || (TK_DIGIT == ch) || (TK_LOWER == ch) || (TK_HASH == ch));
|
|
|
|
x = *++lexical_ptr, ch = ctypetab[x])
|
|
|
|
{
|
|
|
|
if (cp2 < cp3)
|
|
|
|
*cp2++ = x;
|
|
|
|
}
|
2012-03-24 14:06:46 -04:00
|
|
|
(TREF(director_ident)).len = INTCAST(cp2 - ident_buffer);
|
|
|
|
TREF(director_token) = TK_IDENT;
|
|
|
|
memcpy((TREF(director_ident)).addr, ident_buffer, (TREF(director_ident)).len);
|
2012-02-05 11:35:58 -05:00
|
|
|
advancewindow(); /* Makes the homogenized token the current token (again) and prereads next token */
|
|
|
|
}
|
|
|
|
#endif
|