version 1.50, 2014/10/10 14:02:02 |
version 1.51, 2014/10/10 14:27:46 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 554 eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par |
|
Line 554 eqn_box_alloc(struct eqn_node *ep, struct eqn_box *par |
|
* The new EQN_SUBEXPR will have a two-child limit. |
* The new EQN_SUBEXPR will have a two-child limit. |
*/ |
*/ |
static struct eqn_box * |
static struct eqn_box * |
eqn_box_makebinary(struct eqn_node *ep, |
eqn_box_makebinary(struct eqn_node *ep, |
enum eqn_post pos, struct eqn_box *parent) |
enum eqn_post pos, struct eqn_box *parent) |
{ |
{ |
struct eqn_box *b, *newb; |
struct eqn_box *b, *newb; |
Line 666 eqn_parse(struct eqn_node *ep, struct eqn_box *parent) |
|
Line 666 eqn_parse(struct eqn_node *ep, struct eqn_box *parent) |
|
|
|
assert(NULL != parent); |
assert(NULL != parent); |
again: |
again: |
|
|
switch ((tok = eqn_tok_parse(ep, &p))) { |
switch ((tok = eqn_tok_parse(ep, &p))) { |
case (EQN_TOK_UNDEF): |
case (EQN_TOK_UNDEF): |
if ((rc = eqn_undef(ep)) <= 0) |
if ((rc = eqn_undef(ep)) <= 0) |
|
|
case (EQN_TOK_TDEFINE): |
case (EQN_TOK_TDEFINE): |
if (NULL == eqn_nextrawtok(ep, NULL)) |
if (NULL == eqn_nextrawtok(ep, NULL)) |
EQN_MSG(MANDOCERR_EQNEOF, ep); |
EQN_MSG(MANDOCERR_EQNEOF, ep); |
else if (NULL == eqn_next(ep, |
else if (NULL == eqn_next(ep, |
ep->data[(int)ep->cur], NULL, 0)) |
ep->data[(int)ep->cur], NULL, 0)) |
EQN_MSG(MANDOCERR_EQNEOF, ep); |
EQN_MSG(MANDOCERR_EQNEOF, ep); |
break; |
break; |
|
|
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
} |
} |
parent = eqn_box_makebinary |
parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent); |
(ep, EQNPOS_NONE, parent); |
|
parent->type = EQN_LISTONE; |
parent->type = EQN_LISTONE; |
parent->expectargs = 1; |
parent->expectargs = 1; |
switch (tok) { |
switch (tok) { |
|
|
case (EQN_TOK_BACK): |
case (EQN_TOK_BACK): |
case (EQN_TOK_DOWN): |
case (EQN_TOK_DOWN): |
case (EQN_TOK_UP): |
case (EQN_TOK_UP): |
tok = eqn_tok_parse(ep, NULL); |
tok = eqn_tok_parse(ep, NULL); |
if (EQN_TOK__MAX != tok) { |
if (EQN_TOK__MAX != tok) { |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
|
|
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
} |
} |
/* |
/* |
* Accept a left-right-associative set of arguments just |
* Accept a left-right-associative set of arguments just |
* like sub and sup and friends but without rebalancing |
* like sub and sup and friends but without rebalancing |
* under a pivot. |
* under a pivot. |
|
|
* FIXME: this is a shitty sentinel: we should really |
* FIXME: this is a shitty sentinel: we should really |
* have a native EQN_BRACE type or whatnot. |
* have a native EQN_BRACE type or whatnot. |
*/ |
*/ |
while (parent->type != EQN_LIST) |
while (parent->type != EQN_LIST) |
if (NULL == (parent = parent->parent)) { |
if (NULL == (parent = parent->parent)) { |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
|
|
} else if (STRNEQ(start, sz, "floor", 5)) { |
} else if (STRNEQ(start, sz, "floor", 5)) { |
strlcpy(sym, "\\[rf]", sizeof(sym)); |
strlcpy(sym, "\\[rf]", sizeof(sym)); |
parent->right = mandoc_strdup(sym); |
parent->right = mandoc_strdup(sym); |
} else |
} else |
parent->right = mandoc_strndup(start, sz); |
parent->right = mandoc_strndup(start, sz); |
} |
} |
if (NULL == (parent = parent->parent)) { |
if (NULL == (parent = parent->parent)) { |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
} |
} |
if (EQN_TOK_BRACE_CLOSE == tok && parent && |
if (EQN_TOK_BRACE_CLOSE == tok && parent && |
(parent->type == EQN_PILE || |
(parent->type == EQN_PILE || |
parent->type == EQN_MATRIX)) |
parent->type == EQN_MATRIX)) |
parent = parent->parent; |
parent = parent->parent; |
/* Close out any "singleton" lists. */ |
/* Close out any "singleton" lists. */ |
while (parent->type == EQN_LISTONE && |
while (parent->type == EQN_LISTONE && |
parent->args == parent->expectargs) |
parent->args == parent->expectargs) |
if (NULL == (parent = parent->parent)) { |
if (NULL == (parent = parent->parent)) { |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
|
|
} else if (STRNEQ(start, sz, "floor", 5)) { |
} else if (STRNEQ(start, sz, "floor", 5)) { |
strlcpy(sym, "\\[lf]", sizeof(sym)); |
strlcpy(sym, "\\[lf]", sizeof(sym)); |
parent->left = mandoc_strdup(sym); |
parent->left = mandoc_strdup(sym); |
} else |
} else |
parent->left = mandoc_strndup(start, sz); |
parent->left = mandoc_strndup(start, sz); |
} |
} |
break; |
break; |
|
|
parent->type = EQN_LIST; |
parent->type = EQN_LIST; |
break; |
break; |
case (EQN_TOK_ABOVE): |
case (EQN_TOK_ABOVE): |
while (parent->type != EQN_PILE) |
while (parent->type != EQN_PILE) |
if (NULL == (parent = parent->parent)) { |
if (NULL == (parent = parent->parent)) { |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
return(-1); |
return(-1); |
|
|
break; |
break; |
case (EQN_TOK_EOF): |
case (EQN_TOK_EOF): |
/* |
/* |
* End of file! |
* End of file! |
* TODO: make sure we're not in an open subexpression. |
* TODO: make sure we're not in an open subexpression. |
*/ |
*/ |
return(0); |
return(0); |
|
|
cur->type = EQN_TEXT; |
cur->type = EQN_TEXT; |
for (i = 0; i < EQNSYM__MAX; i++) |
for (i = 0; i < EQNSYM__MAX; i++) |
if (0 == strcmp(eqnsyms[i].str, p)) { |
if (0 == strcmp(eqnsyms[i].str, p)) { |
(void)snprintf(sym, sizeof(sym), |
(void)snprintf(sym, sizeof(sym), |
"\\[%s]", eqnsyms[i].sym); |
"\\[%s]", eqnsyms[i].sym); |
cur->text = mandoc_strdup(sym); |
cur->text = mandoc_strdup(sym); |
free(p); |
free(p); |
|
|
/* |
/* |
* Post-process list status. |
* Post-process list status. |
*/ |
*/ |
while (parent->type == EQN_LISTONE && |
while (parent->type == EQN_LISTONE && |
parent->args == parent->expectargs) |
parent->args == parent->expectargs) |
if (NULL == (parent = parent->parent)) { |
if (NULL == (parent = parent->parent)) { |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
EQN_MSG(MANDOCERR_EQNSYNT, ep); |
|
|
} |
} |
|
|
enum rofferr |
enum rofferr |
eqn_end(struct eqn_node **epp) |
eqn_end(struct eqn_node **epp) |
{ |
{ |
struct eqn_node *ep; |
struct eqn_node *ep; |
|
|