#include "stdafx.h"
|
#include "stdafx.h"
|
|
|
|
int Macro::inst = 0;
|
|
|
// Substitute the argument list into the macro body.
|
// Substitute the argument list into the macro body.
|
|
|
char *Macro::SubArgs()
|
char *Macro::SubArgs(Arglist *al)
|
{
|
{
|
char *buf, *bdy;
|
char *buf, *bdy;
|
char *p, *q;
|
char *p, *q;
|
int ndx;
|
int ndx;
|
static char ibuf[16000];
|
int bufsz;
|
|
|
bdy = body;
|
bdy = body;
|
ZeroMemory(ibuf, 16000);
|
buf = new char[16000];
|
for (p = ibuf; *bdy; bdy++) {
|
ZeroMemory(buf, 16000);
|
|
bufsz = 16000;
|
|
for (p = buf; *bdy; bdy++) {
|
// If macro instance indicator found, substitute the instance number.
|
// If macro instance indicator found, substitute the instance number.
|
if (*bdy == '@')
|
if (*bdy == '@') {
|
p += sprintf_s(p, 16000 - (p-buf), "%d", inst);
|
p += sprintf_s(p, bufsz - (p - buf), "%d", inst);
|
|
*p = '\0';
|
|
}
|
else if (*bdy == MACRO_PARM_MARKER) {
|
else if (*bdy == MACRO_PARM_MARKER) {
|
if (isdigit(*(bdy+1))) {
|
if (isdigit(*(bdy+1))) {
|
bdy++;
|
bdy++;
|
ndx = *bdy - '0';
|
ndx = *bdy - '0';
|
if (ndx < args->count) {
|
if (ndx < parms.count && ndx < al->count) {
|
// Copy the argument from the arg list to the output buffer.
|
// Copy the parameter from the arg list to the output buffer.
|
for (q = args->arg[ndx]->text; *q; q++) {
|
if (&buf[bufsz] - p > al->args[ndx].text.length()) {
|
*p = *q;
|
strcpy(p, (char *)al->args[ndx].text.c_str());
|
p++;
|
while (*p) p++;
|
}
|
}
|
}
|
}
|
printf("Not enough args for substitution. %d\r\n", lineno);
|
|
}
|
}
|
else {
|
else {
|
*p = *bdy;
|
*p = *bdy;
|
p++;
|
p++;
|
}
|
}
|
}
|
}
|
// Not a parameter marker, just copy text to output.
|
// Not a parameter marker, just copy text to output.
|
else {
|
else {
|
*p = *bdy;
|
*p = *bdy;
|
p++;
|
p++;
|
}
|
}
|
|
if (&buf[bufsz] - p < 20) {
|
|
ndx = p - buf;
|
|
q = new char[bufsz + 10000];
|
|
memcpy(q, buf, bufsz);
|
|
bufsz += 10000;
|
|
delete[] buf;
|
|
buf = q;
|
|
p = &buf[ndx];
|
}
|
}
|
buf = new char[strlen(ibuf)+1];
|
}
|
memcpy(buf, ibuf, strlen(ibuf)+1);
|
*p = '\0';
|
return (buf);
|
return (buf);
|
}
|
}
|
|
|
|
|
|
void SkipBlockComment()
|
|
{
|
|
char c;
|
|
|
|
do {
|
|
c = *inptr;
|
|
inptr++;
|
|
if (c == '*') {
|
|
c = *inptr;
|
|
inptr++;
|
|
if (c == '/')
|
|
break;
|
|
--inptr;
|
|
}
|
|
} while (c > 0);
|
|
}
|
|
|
|
int ProcessUnquoted()
|
|
{
|
|
char c;
|
|
|
|
c = *inptr;
|
|
if (c == '/') {
|
|
c = *inptr;
|
|
inptr++;
|
|
c = *inptr;
|
|
inptr++;
|
|
// Block comment ?
|
|
if (c == '*') {
|
|
SkipBlockComment();
|
|
c = *inptr;
|
|
if (c > 0)
|
|
return (1);
|
|
else {
|
|
printf("End of file in block comment. %d\n", lineno);
|
|
return (0);
|
|
}
|
|
}
|
|
// Comment to EOL ?
|
|
else if (c == '/') {
|
|
ScanToEOL();
|
|
c = *inptr;
|
|
if (c > 0)
|
|
return (0);
|
|
}
|
|
else {
|
|
c = '/';
|
|
--inptr;
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
int CountLeadingSpaces()
|
|
{
|
|
int count;
|
|
|
|
count = 0;
|
|
while (*inptr == ' ' || *inptr == '\t') {
|
|
inptr++;
|
|
count++;
|
|
}
|
|
return (count);
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
// Description :
|
// Description :
|
// Gets the body of a macro. All macro bodies must be < 2k in size. Macro
|
// Gets the body of a macro. All macro bodies must be < 2k in size. Macro
|
// parameters are matched up with their positions in the macro. A $<number>
|
// parameters are matched up with their positions in the macro. A $<number>
|
// (as in $1, $2, etc) is substituted in the macro body in place of the
|
// (as in $1, $2, etc) is substituted in the macro body in place of the
|
// parameter name (we don't actually care what the parameter name is).
|
// parameter name (we don't actually care what the parameter name is).
|
// Macros continued on the next line with '\' are also processed. The
|
// Macros continued on the next line with '\' are also processed. The
|
// newline is removed from the macro.
|
// newline is removed from the macro.
|
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
|
|
char *Macro::GetBody(char *parmlist[])
|
char *Macro::GetBody()
|
{
|
{
|
char *b, *id = NULL, *p1, *p2;
|
char *b, *id = NULL, *p1, *p2;
|
static char buf[16000];
|
char *buf;
|
int ii, found, c;
|
int ii, found, c;
|
int InQuote = 0;
|
int InQuote = 0;
|
int count = sizeof(buf)-1;
|
int count = 16000;
|
|
bool abort = false;
|
|
|
|
try {
|
|
buf = new char[count];
|
|
ZeroMemory(buf, count);
|
SkipSpaces();
|
SkipSpaces();
|
memset(buf, 0, sizeof(buf));
|
for (b = buf; count >= 0; )
|
for (b = buf; count >= 0; b++, --count)
|
|
{
|
{
|
// First search for an identifier to substitute with parameter
|
// First search for an identifier to substitute with parameter
|
if (parmlist) {
|
if (parms.count > 0) {
|
while (*inptr == ' ' || *inptr == '\t') {
|
ii = CountLeadingSpaces();
|
*b++ = *inptr;
|
count -= ii;
|
inptr++;
|
|
count--;
|
|
if (count < 0)
|
if (count < 0)
|
goto jmp1;
|
break;
|
}
|
memcpy(b, inptr - ii, ii);
|
|
b += ii;
|
p1 = inptr;
|
p1 = inptr;
|
id = getIdentifier();
|
NextToken();
|
p2 = inptr;
|
p2 = inptr;
|
if (id) {
|
if (token == tk_endm)
|
for (found = ii = 0; parmlist[ii]; ii++)
|
break;
|
if (strcmp(parmlist[ii], id) == 0) {
|
if (token == tk_id) {
|
*b = '';
|
for (found = ii = 0; ii < parms.count && !abort; ii++) {
|
|
if (parms.args[ii].text.compare(lastid) == 0) {
|
|
*b = '\x14';
|
b++;
|
b++;
|
count--;
|
count--;
|
if (count < 0)
|
if (count < 0) {
|
goto jmp1;
|
abort = true;
|
|
}
|
|
else {
|
*b = '0' + (char)ii;
|
*b = '0' + (char)ii;
|
|
b++;
|
found = 1;
|
found = 1;
|
break;
|
break;
|
}
|
}
|
|
}
|
|
}
|
|
if (abort)
|
|
break;
|
// if the identifier was not a parameter then just copy it to
|
// if the identifier was not a parameter then just copy it to
|
// the macro body
|
// the macro body
|
if (!found) {
|
if (!found) {
|
strncpy(b, p1, p2-p1);
|
count -= p2 - p1;
|
count -= p2 -p1 - 1;
|
|
if (count < 0)
|
if (count < 0)
|
goto jmp1;
|
break;
|
b += p2-p1-1; // b will be incremented at end of loop
|
memcpy(b, p1, p2 - p1);
|
|
b += p2 - p1;
|
}
|
}
|
}
|
}
|
else
|
else
|
inptr = p1; // reset inptr if no identifier found
|
inptr = p1; // reset inptr if no identifier found
|
}
|
}
|
if (id == NULL) {
|
if (token == tk_endm)
|
|
break;
|
|
if (token != tk_id) {
|
|
memcpy(b, p1, p2 - p1);
|
|
b += p2 - p1;
|
|
inptr = p2;
|
c = *inptr;
|
c = *inptr;
|
|
//inptr++;
|
|
if (c == '"') {
|
inptr++;
|
inptr++;
|
if (c == '"')
|
|
InQuote = !InQuote;
|
InQuote = !InQuote;
|
|
}
|
if (!InQuote) {
|
if (!InQuote) {
|
if (c == '/') {
|
p1 = inptr;
|
c = *inptr;
|
c = ProcessUnquoted();
|
inptr++;
|
if (count - (inptr - p1) < 0) {
|
c = NextCh();
|
count = -1;
|
// Block comment ?
|
|
if (c == '*') {
|
|
while(c > 0) {
|
|
c = *inptr;
|
|
inptr++;
|
|
if (c == '*') {
|
|
c = *inptr;
|
|
inptr++;
|
|
if (c == '/')
|
|
break;
|
break;
|
--inptr;
|
|
}
|
}
|
|
memcpy(b, p1, (inptr - p1));
|
|
b += (inptr - p1);
|
|
if (c == 0)
|
|
break;
|
|
c = inptr[-1];
|
}
|
}
|
if (c > 0) {
|
if (c < 1) {
|
--b;
|
if (InQuote)
|
continue;
|
printf("End of file in quote. %d\n", lineno);
|
|
break;
|
}
|
}
|
else
|
|
printf("End of line in comment. %d\n", lineno);
|
|
}
|
}
|
// Comment to EOL ?
|
|
else if (c == '/') {
|
|
while(c != '\n' && c > 0) { c = *inptr; inptr++; }
|
|
if (c > 0) {
|
|
--b;
|
|
++count;
|
|
goto jmp1;
|
|
}
|
}
|
|
|
|
if (count < 0) {
|
|
delete[] buf;
|
|
printf("Expanded macro is too large. %d\n", lineno);
|
|
body = new char[20];
|
|
strcpy(body, "<too large>");
|
|
return (body);
|
}
|
}
|
else {
|
else {
|
c = '/';
|
*b = '\0';
|
--inptr;
|
--b;
|
}
|
// Trim off trailing spaces.
|
}
|
while ((*b == ' ' || *b == '\t') && b > buf) {
|
else if (c == '\\') // check for continuation onto next line
|
b--;
|
{
|
|
while (c != '\n' && c > 0) { c= *inptr; inptr++}
|
|
if (c > 0) {
|
|
--b; // b will be incremented but we haven't got a character
|
|
++count;
|
|
SkipSpaces(); // Skip leading spaces on next line
|
|
continue;
|
|
}
|
|
}
|
|
}
|
}
|
if (c == '\n' || c < 1) {
|
b++;
|
if (InQuote)
|
*b = '\0';
|
printf("End of file in comment. %d\n", lineno);
|
body = new char[strlen(buf) + 10];
|
break;
|
strcpy(body, buf);
|
|
delete[] buf;
|
|
return (body);
|
}
|
}
|
*b = c;
|
|
}
|
}
|
|
catch (...) {
|
|
printf("Thrown error\n");
|
}
|
}
|
jmp1:
|
|
if (count < 0)
|
|
printf("Expanded macro is too large. %d\n", lineno);
|
|
*b = 0;
|
|
rtrim(buf); // Trim off trailing spaces.
|
|
return buf;
|
|
}
|
}
|
|
|
|
|
void Arg::Clear()
|
void Arg::Clear()
|
{
|
{
|
ZeroMemory(text,sizeof(text));
|
text = "";
|
}
|
}
|
|
|
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
// Description :
|
// Description :
|
// Gets an argument to be substituted into a macro body. Note that the
|
// Gets an argument to be substituted into a macro body. Note that the
|
// round bracket nesting level is kept track of so that a comma in the
|
// round bracket nesting level is kept track of so that a comma in the
|
// middle of an argument isn't inadvertently picked up as an argument
|
// middle of an argument isn't inadvertently picked up as an argument
|
// separator.
|
// separator.
|
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
|
|
void Arg::Get()
|
void Arg::Get()
|
{
|
{
|
int Depth = 0;
|
int Depth = 0;
|
int c;
|
int c;
|
char *argstr = text;
|
char ch;
|
|
char *st;
|
|
|
SkipSpaces();
|
SkipSpaces();
|
ZeroMemory(text,sizeof(text));
|
st = inptr;
|
while(1)
|
while(1)
|
{
|
{
|
if (argstr-text > sizeof(text)-2) {
|
|
printf("Macro argument too large %d. Is a ')' missing ?\n",lineno);
|
|
break;
|
|
}
|
|
c = *inptr;
|
c = *inptr;
|
inptr++;
|
inptr++;
|
if (c < 1) {
|
if (c < 1) {
|
if (Depth > 0)
|
if (Depth > 0)
|
printf("err16\r\n");
|
printf("err16\r\n");
|
break;
|
break;
|
}
|
}
|
if (c == '(')
|
if (c == '(')
|
Depth++;
|
Depth++;
|
else if (c == ')') {
|
else if (c == ')') {
|
if (Depth < 1) { // check if we hit the end of the arg list
|
if (Depth < 1) { // check if we hit the end of the arg list
|
--inptr;
|
--inptr;
|
break;
|
break;
|
}
|
}
|
Depth--;
|
Depth--;
|
}
|
}
|
else if (Depth == 0 && c == ',') { // comma at outermost level means
|
else if (Depth == 0 && c == ',') { // comma at outermost level means
|
--inptr;
|
--inptr;
|
break; // end of argument has been found
|
break; // end of argument has been found
|
}
|
}
|
else if (Depth == 0 && (c=='\r' || c=='\n')) {
|
else if (Depth == 0 && (c=='\r' || c=='\n')) {
|
--inptr;
|
--inptr;
|
break;
|
break;
|
}
|
}
|
*argstr++ = c; // copy input argument to argstr.
|
|
}
|
}
|
|
ch = *inptr;
|
|
*inptr = '\0';
|
|
text = std::string(st);
|
|
*inptr = ch;
|
// if (argbuf[0])
|
// if (argbuf[0])
|
// if (fdbg) fprintf(fdbg," macro arg<%s>\r\n",argbuf);
|
// if (fdbg) fprintf(fdbg," macro arg<%s>\r\n",argbuf);
|
return;
|
return;
|
}
|
}
|
|
|
void Arglist::Get()
|
void Arglist::Get()
|
{
|
{
|
int nn;
|
int nn;
|
char lastch;
|
char lastch;
|
|
bool done = false;
|
|
|
for (nn = 0; nn < 10; nn++)
|
for (nn = 0; nn < 10; nn++)
|
args[nn]->Clear();
|
args[nn].Clear();
|
for (nn = 0; nn < 10; nn++) {
|
count = 0;
|
args[nn]->Get();
|
j1:
|
if (*inptr != ',') {
|
|
SkipSpaces();
|
SkipSpaces();
|
break;
|
switch (*inptr) {
|
}
|
case '\n':
|
inptr++; // skip over ,
|
|
}
|
|
args->count = nn;
|
|
while (*inptr) {
|
|
if (*inptr==0)
|
|
break;
|
|
if (*inptr=='\n') {
|
|
lineno++;
|
lineno++;
|
|
case '\r':
|
|
inptr++;
|
|
goto j1;
|
|
case '(':
|
|
inptr++;
|
|
SkipSpaces();
|
|
for (; count < 10 && !done; count++) {
|
|
args[count].Get();
|
|
switch (*inptr) {
|
|
// Arg list can continue on next line
|
|
case '\n':
|
|
lineno++;
|
|
case '\r':
|
|
inptr++;
|
|
continue;
|
|
case ')':
|
|
done = true;
|
inptr++;
|
inptr++;
|
break;
|
break;
|
}
|
case ',':
|
|
inptr++;
|
|
SkipSpaces();
|
|
continue;
|
|
case '\0':
|
|
break;
|
|
default:
|
inptr++;
|
inptr++;
|
}
|
}
|
}
|
}
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
// Description :
|
// Description :
|
// Used during the definition of a macro to get the associated parameter
|
// Used during the definition of a macro to get the associated parameter
|
// list.
|
// list.
|
//
|
//
|
// Returns
|
// Returns
|
// pointer to first parameter in list.
|
// pointer to first parameter in list.
|
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
|
|
int Macro::GetParmList(char *parmlist[])
|
int Macro::GetParmList()
|
{
|
{
|
int id;
|
int id;
|
int Depth = 0, c, count;
|
int Depth = 0, c;
|
|
|
count = 0;
|
parms.count = 0;
|
while(1)
|
while(1)
|
{
|
{
|
id = getIdentifier();
|
NextToken();
|
if (id!=0) {
|
if (token==tk_id) {
|
if (count >= 20) {
|
if (parms.count >= 20) {
|
printf("Too many macro parameters %d.\n", lineno);
|
printf("Too many macro parameters %d.\n", lineno);
|
goto errxit;
|
goto errxit;
|
}
|
}
|
parmlist[count] = _strdup(lastid);
|
parms.args[parms.count].text = std::string(lastid);
|
if (parmlist[count] == NULL)
|
parms.count++;
|
printf("Insufficient memory %d\n", lineno);
|
|
count++;
|
|
}
|
}
|
do {
|
do {
|
SkipSpaces();
|
SkipSpaces();
|
c = *inptr;
|
c = *inptr;
|
inptr++;
|
inptr++;
|
if (c=='\\') {
|
if (c=='\\') {
|
ScanToEOL();
|
ScanToEOL();
|
inptr++;
|
inptr++;
|
}
|
}
|
}
|
}
|
while (c=='\\');
|
while (c=='\\');
|
if (c == ')') { // we've gotten our last parameter
|
if (c == ')') { // we've gotten our last parameter
|
inptr--;
|
inptr--;
|
break;
|
break;
|
}
|
}
|
if (c != ',') {
|
if (c != ',') {
|
printf("Expecting ',' in macro parameter list %d.\n", lineno);
|
printf("Expecting ',' in macro parameter list %d.\n", lineno);
|
goto errxit;
|
goto errxit;
|
}
|
}
|
}
|
}
|
// if (count < 1)
|
|
// err(17);
|
|
if (count < 20)
|
|
parmlist[count] = NULL;
|
|
errxit:;
|
errxit:;
|
return count;
|
return (parms.count);
|
}
|
}
|
|
|
|
|
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
// Description :
|
// Description :
|
// Copies a macro into the input buffer. Resets the input buffer pointer
|
// Copies a macro into the input buffer. Resets the input buffer pointer
|
// to the start of the macro.
|
// to the start of the macro.
|
//
|
//
|
// slen; - the number of characters being substituted
|
// slen; - the number of characters being substituted
|
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
|
|
void Macro::Substitute(char *body, int slen)
|
void Macro::Substitute(char *what, int slen)
|
{
|
{
|
int mlen, dif, nchars;
|
int mlen, dif, nchars;
|
int nn;
|
int nn;
|
char *p;
|
char *p;
|
|
|
mlen = strlen(body); // macro length
|
mlen = strlen(what); // macro length
|
dif = mlen - slen;
|
dif = mlen - slen;
|
nchars = inptr-masterFile; // calculate number of characters that could be remaining
|
nchars = inptr-masterFile; // calculate number of characters that could be remaining
|
memmove(inptr+dif, inptr, sizeof(masterFile)-500-nchars-dif); // shift open space in input buffer
|
if (dif > 10000) {
|
|
p = new char[masterFileLength + dif + 10000];
|
|
memcpy(p, masterFile, masterFileLength);
|
|
masterFile = p;
|
|
masterFileLength = masterFileLength + dif + 10000;
|
|
inptr = &masterFile[nchars];
|
|
}
|
|
memmove(inptr+dif, inptr, masterFileLength-500-nchars-dif); // shift open space in input buffer
|
inptr -= slen; // reset input pointer to start of replaced text
|
inptr -= slen; // reset input pointer to start of replaced text
|
memcpy(inptr, body, mlen); // copy macro body in place over identifier
|
memcpy(inptr, what, mlen); // copy macro body in place over identifier
|
|
inst++;
|
}
|
}
|
|
|
|
|