Print parse trees with infix notation

Fixes #62.
This commit is contained in:
Glen Whitney 2019-08-24 15:17:35 -07:00
parent 96079b210e
commit 9670e8b4a1
3 changed files with 80 additions and 11 deletions

View File

@ -249,9 +249,9 @@ static int print_string(char* dest, size_t space,
/*}}}*/ /*}}}*/
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/ /* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
size_t printtok(char* dest, size_t size, size_t field_width, size_t ptokatprec(char* dest, size_t size, size_t field_width, StringFormat sf,
StringFormat sf, FloatFormat ff, FloatFormat ff, int digits, ErrorFormat ef, const Token *tok,
int digits, ErrorFormat ef, const Token *tok) FunctionPrecedence atprec)
{ {
if (debug_level > 2) { if (debug_level > 2) {
printf("..Entering printtok; bufsize %d, field_width %d, qs %d, ff %s," printf("..Entering printtok; bufsize %d, field_width %d, qs %d, ff %s,"
@ -381,17 +381,76 @@ size_t printtok(char* dest, size_t size, size_t field_width,
/* FUNCALL */ /*{{{*/ /* FUNCALL */ /*{{{*/
case FUNCALL: case FUNCALL:
{ {
cur += print_fident(dest+cur, size-cur-1, tok->u.funcall.fident); FunctionIdentifier fid = tok->u.funcall.fident;
if (tok->u.funcall.argc >= 0 && cur + 2 < size) /* -1 args is bare func */ if (tok->u.funcall.argc <= 0)
{ {
dest[cur++] = '\('; cur += print_fident(dest+cur, size-cur-1, fid);
if (tok->u.funcall.argc == 0)
{
if (cur < size - 2) { dest[cur++] = '('; dest[cur++] = ')'; }
else cur += 2;
}
break;
}
FunctionPrecedence fp = tfunc[fid].precedence;
switch (fp)
{
case PREFIX_FUNC: {
cur += print_fident(dest+cur, size-cur-1, fid);
if (cur < size) dest[cur++] = '(';
for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai) for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
{ {
if (ai > 0 && cur < size) dest[cur++] = ','; if (ai > 0 && cur < size) dest[cur++] = ',';
cur += printtok(dest+cur, size-cur-1, field_width-cur, sf, ff, /* The commas eliminate the need for precedence worries in arguments*/
digits, ef, tok->u.funcall.argv + ai); cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
digits, ef, tok->u.funcall.argv + ai,
NO_PRECEDENCE);
} }
if (cur < size) dest[cur++] = ')'; if (cur < size) dest[cur++] = ')';
break;
}
case PREFIX_NEG: {
assert(tok->u.funcall.argc == 1);
assert(tfunc[fid].display_symbol != NULL);
if (fp < atprec && cur < size) dest[cur++] = '(';
if (cur < size) {
strncpy(dest+cur, tfunc[fid].display_symbol, size-cur-1);
cur += strlen(tfunc[fid].display_symbol);
}
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
digits, ef, tok->u.funcall.argv, fp);
if (fp < atprec && cur < size) dest[cur++] = ')';
break;
}
default: /* infix argument */
assert(tok->u.funcall.argc > 1);
if (fp < atprec && cur < size) dest[cur++] = '(';
for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ ai)
{
bool parenarg = false;
if (ai > 0) {
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
const char *use = tfunc[fid].display_symbol;
if (use == NULL) use = tfunc[fid].name;
strncpy(dest+cur, use, size-cur-1);
cur += strlen(use);
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
} else if (fp > PREFIX_NEG) {
char powbuf[4096];
size_t arglen = ptokatprec(powbuf, sizeof(powbuf), 0, sf, ff,
digits, ef, tok->u.funcall.argv, fp);
assert(arglen < sizeof(powbuf)-1);
if (powbuf[0] == '-') {
parenarg = true;
if (cur < size) dest[cur++] = '(';
}
}
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
digits, ef, tok->u.funcall.argv + ai, fp);
if (parenarg && cur < size) dest[cur++] = ')';
}
if (fp < atprec && cur < size) dest[cur++] = ')';
break;
} }
break; break;
} }
@ -439,6 +498,16 @@ size_t printtok(char* dest, size_t size, size_t field_width,
} }
/*}}}*/ /*}}}*/
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
size_t printtok(char* dest, size_t size, size_t field_width,
StringFormat sf, FloatFormat ff,
int digits, ErrorFormat ef, const Token *tok)
{
return ptokatprec(dest, size, field_width, sf, ff, digits, ef, tok,
NO_PRECEDENCE);
}
/*}}}*/
/* print -- print token sequence */ /*{{{*/ /* print -- print token sequence */ /*{{{*/
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff, void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
int digits, Token **n) int digits, Token **n)

View File

@ -390,7 +390,7 @@ static Token at_func(int argc, const Token argv[], LocConvention lcon)
strcat(result.u.err, location.u.err); strcat(result.u.err, location.u.err);
/* don't free the location if it is the same as an argument, because /* don't free the location if it is the same as an argument, because
those get freed later: */ those get freed later: */
for (size_t i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
if (argv[i].type == EEK & argv[i].u.err == location.u.err) return result; if (argv[i].type == EEK & argv[i].u.err == location.u.err) return result;
tfree(&location); tfree(&location);
return result; return result;

View File

@ -36,8 +36,8 @@ typedef struct Token_struc Token;
typedef enum /* In increasing order of precedence */ typedef enum /* In increasing order of precedence */
{ {
INFIX_CONC, INFIX_REL, INFIX_PLUS, INFIX_MUL, PREFIX_NEG, NO_PRECEDENCE, INFIX_CONC, INFIX_REL, INFIX_PLUS, INFIX_MUL,
INFIX_POW, PREFIX_FUNC PREFIX_NEG, INFIX_POW, PREFIX_FUNC
} FunctionPrecedence; } FunctionPrecedence;
typedef enum { FUNCT, MACRO } EvaluationStrategy; typedef enum { FUNCT, MACRO } EvaluationStrategy;