aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2011-07-21 12:30:44 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2011-07-21 12:30:44 +0000
commitbb4fb107c337c4a2ff9653f44eb52a91acfe6b4a (patch)
tree311bb493dc3cf6ba1f6495455fa0b26d81ecda6d
parente0f75c6ac153f58d4ab0b61182736fc07a2ce1dc (diff)
downloadmandoc-bb4fb107c337c4a2ff9653f44eb52a91acfe6b4a.tar.gz
mandoc-bb4fb107c337c4a2ff9653f44eb52a91acfe6b4a.tar.zst
mandoc-bb4fb107c337c4a2ff9653f44eb52a91acfe6b4a.zip
Support nested `{, }' subexpressions in eqn. Document in code.
-rw-r--r--eqn.c61
-rw-r--r--mandoc.h23
-rw-r--r--read.c4
-rw-r--r--tree.c13
4 files changed, 77 insertions, 24 deletions
diff --git a/eqn.c b/eqn.c
index 8383a878..9aa0af78 100644
--- a/eqn.c
+++ b/eqn.c
@@ -1,4 +1,4 @@
-/* $Id: eqn.c,v 1.14 2011/07/21 11:57:56 kristaps Exp $ */
+/* $Id: eqn.c,v 1.15 2011/07/21 12:30:44 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -54,7 +54,8 @@ static const char *eqn_nexttok(struct eqn_node *, size_t *);
static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
static const char *eqn_next(struct eqn_node *,
char, size_t *, int);
-static int eqn_box(struct eqn_node *, struct eqn_box *);
+static int eqn_box(struct eqn_node *,
+ struct eqn_box *, struct eqn_box **);
static const struct eqnpart eqnparts[EQN__MAX] = {
{ "define", 6, eqn_do_define }, /* EQN_DEFINE */
@@ -119,7 +120,8 @@ eqn_alloc(int pos, int line, struct mparse *parse)
enum rofferr
eqn_end(struct eqn_node *ep)
{
- struct eqn_box *root;
+ struct eqn_box *root, *last;
+ int c;
ep->eqn.root = root =
mandoc_calloc(1, sizeof(struct eqn_box));
@@ -129,21 +131,38 @@ eqn_end(struct eqn_node *ep)
return(ROFF_IGN);
/*
- * Validate the expression.
- * Use the grammar found in the literature.
+ * Run the parser.
+ * If we return before reaching the end of our input, our scope
+ * is still open somewhere.
+ * If we return alright but don't have a symmetric scoping, then
+ * something's not right either.
+ * Otherwise, return the equation.
*/
- return(eqn_box(ep, root) < 0 ? ROFF_IGN : ROFF_EQN);
+ if ((c = eqn_box(ep, root, &last)) > 0) {
+ EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
+ c = 0;
+ } else if (0 == c && last != root)
+ EQN_MSG(MANDOCERR_EQNSCOPE, ep);
+
+ return(1 == c ? ROFF_EQN : ROFF_IGN);
}
static int
-eqn_box(struct eqn_node *ep, struct eqn_box *last)
+eqn_box(struct eqn_node *ep, struct eqn_box *last, struct eqn_box **sv)
{
size_t sz;
const char *start;
- int i, nextc;
+ int c, i, nextc;
struct eqn_box *bp;
+ /*
+ * Mark our last level of subexpression.
+ * Also mark whether that the next node should be a
+ * subexpression node.
+ */
+
+ *sv = last;
nextc = 1;
again:
if (NULL == (start = eqn_nexttok(ep, &sz)))
@@ -160,19 +179,39 @@ again:
goto again;
}
- bp = mandoc_calloc(1, sizeof(struct eqn_box));
- bp->type = EQN_TEXT;
+ /* Exit this [hopefully] subexpression. */
+ if (sz == 1 && 0 == strncmp("}", start, 1))
+ return(1);
+
+ bp = mandoc_calloc(1, sizeof(struct eqn_box));
if (nextc)
last->child = bp;
else
last->next = bp;
+ last = bp;
+
+ /*
+ * See if we're to open a new subexpression.
+ * If so, mark our node as such and descend.
+ */
+
+ if (sz == 1 && 0 == strncmp("{", start, 1)) {
+ bp->type = EQN_SUBEXPR;
+ c = eqn_box(ep, bp, sv);
+
+ nextc = 0;
+ goto again;
+ }
+
+ /* A regular text node. */
+
+ bp->type = EQN_TEXT;
bp->text = mandoc_malloc(sz + 1);
*bp->text = '\0';
strlcat(bp->text, start, sz + 1);
- last = bp;
nextc = 0;
goto again;
}
diff --git a/mandoc.h b/mandoc.h
index 7c46c763..b585ace8 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -1,4 +1,4 @@
-/* $Id: mandoc.h,v 1.83 2011/07/21 11:34:53 kristaps Exp $ */
+/* $Id: mandoc.h,v 1.84 2011/07/21 12:30:44 kristaps Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -112,6 +112,8 @@ enum mandocerr {
/* related to equations */
MANDOCERR_EQNARGS, /* bad equation macro arguments */
MANDOCERR_EQNNEST, /* too many nested equation defines */
+ MANDOCERR_EQNNSCOPE, /* unexpected equation scope closure*/
+ MANDOCERR_EQNSCOPE, /* equation scope open on exit */
/* related to tables */
MANDOCERR_TBL, /* bad table syntax */
@@ -278,19 +280,24 @@ struct tbl_span {
};
enum eqn_boxt {
- EQN_ROOT,
- EQN_TEXT
+ EQN_ROOT, /* root of parse tree */
+ EQN_TEXT, /* text (number, variable, whatever) */
+ EQN_SUBEXPR /* nested subexpression */
};
+/*
+ * A "box" is a parsed mathematical expression as defined by the eqn.7
+ * grammar.
+ */
struct eqn_box {
- enum eqn_boxt type;
- struct eqn_box *child;
- struct eqn_box *next;
- char *text;
+ enum eqn_boxt type; /* type of node */
+ struct eqn_box *child; /* child node */
+ struct eqn_box *next; /* next in tree */
+ char *text; /* text (or NULL) */
};
struct eqn {
- struct eqn_box *root;
+ struct eqn_box *root; /* root mathematical expression */
int ln; /* invocation line */
int pos; /* invocation position */
};
diff --git a/read.c b/read.c
index 8d59b23f..c79f080f 100644
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/* $Id: read.c,v 1.19 2011/07/18 14:30:51 kristaps Exp $ */
+/* $Id: read.c,v 1.20 2011/07/21 12:30:44 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -154,6 +154,8 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
/* related to equations */
"bad equation macro syntax",
"too many nested equation defines",
+ "unexpected equation scope closure",
+ "equation scope open on exit",
/* related to tables */
"bad table syntax",
diff --git a/tree.c b/tree.c
index a446fb14..0b05b5ea 100644
--- a/tree.c
+++ b/tree.c
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.38 2011/07/21 11:34:53 kristaps Exp $ */
+/* $Id: tree.c,v 1.39 2011/07/21 12:30:44 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -272,14 +272,19 @@ print_box(const struct eqn_box *ep, int indent)
case (EQN_ROOT):
puts("eqn-root");
print_box(ep->child, indent + 1);
- return;
+ break;
+ case (EQN_SUBEXPR):
+ puts("eqn-subxpr");
+ print_box(ep->child, indent + 1);
+ break;
case (EQN_TEXT):
printf("eqn-text: [%s]\n", ep->text);
- print_box(ep->next, indent);
- return;
+ break;
default:
break;
}
+
+ print_box(ep->next, indent);
}
static void