2 * neateqn preprocessor of neatroff
4 * Copyright (C) 2014 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
14 #define FN2(fn) ((!(fn)[1] && ((fn)[0] == 'I' || (fn)[0] == '2')) ? T_ITALIC : 0)
16 /* flags passed to eqn_box() */
17 #define EQN_TSMASK 0x00ffff /* style mask */
18 #define EQN_TOP 0x010000 /* top-level boxes */
19 #define EQN_SUB 0x020000 /* this is a subscript */
20 #define EQN_FROM 0x040000 /* this is a from block */
22 static char gfont
[FNLEN
] = "2";
23 static char grfont
[FNLEN
] = "1";
24 static char gbfont
[FNLEN
] = "3";
25 static char gsize
[FNLEN
] = "\\n[" EQNSZ
"]";
26 static char eqn_lineup
[128]; /* the lineup horizontal request */
27 static int eqn_lineupreg
; /* the number register holding lineup width */
28 static int eqn_mk
; /* the value of MK */
30 static struct box
*eqn_box(int flg
, struct box
*pre
, int sz0
, char *fn0
);
32 /* read equations until delim is read */
33 static int eqn_boxuntil(struct box
*box
, int sz0
, char *fn0
, char *delim
)
35 struct box
*sub
= NULL
;
36 while (tok_get() && tok_jmp(delim
)) {
37 if (!strcmp("}", tok_get()))
39 sub
= eqn_box(box
->style
, sub
? box
: NULL
, sz0
, fn0
);
46 /* update sz0 by sz1 and write it into sz */
47 static void sizeupdate(int dst
, int src
, char *new)
49 if (new[0] == '-' || new[0] == '+')
50 printf(".nr %s %s%s\n", nregname(dst
), nreg(src
), new);
52 printf(".nr %s %s\n", nregname(dst
), new);
56 static void sizesub(int dst
, int src
, int style
, int src_style
)
58 if (TS_SZ(style
) > TS_SZ(src_style
)) {
59 printf(".nr %s %s*7/10\n", nregname(dst
), nreg(src
));
60 printf(".if %s<%d .nr %s %d\n",
61 nreg(dst
), e_minimumsize
,
62 nregname(dst
), e_minimumsize
);
64 printf(".nr %s %s\n", nregname(dst
), nreg(src
));
68 static char *tok_removequotes(char *s
)
71 s
[strlen(s
) - 1] = '\0';
77 static char *tok_improve(char *s
)
79 if (s
[0] == '-' && s
[1] == '\0')
81 if (s
[0] == '+' && s
[1] == '\0')
83 return tok_removequotes(s
);
86 static int eqn_commands(struct box
*box
, int szreg
)
90 if (!tok_jmp("delim")) {
94 if (!tok_jmp("define")) {
99 box_puttext(box
, T_GAP
, "\\h'%du*%sp/100u'",
104 box_puttext(box
, T_GAP
, "\\h'%du*%sp/100u'",
108 if (!tok_jmp("\t")) {
109 box_puttext(box
, T_GAP
, "\t");
112 if (!tok_jmp("gfont")) {
113 strcpy(gfont
, tok_removequotes(tok_poptext()));
116 if (!tok_jmp("grfont")) {
117 strcpy(grfont
, tok_removequotes(tok_poptext()));
120 if (!tok_jmp("gbfont")) {
121 strcpy(gbfont
, tok_removequotes(tok_poptext()));
124 if (!tok_jmp("gsize")) {
125 sz
= tok_removequotes(tok_poptext());
126 if (sz
[0] == '-' || sz
[0] == '+')
127 sprintf(gsize
, "\\n%s%s", escarg(EQNSZ
), sz
);
132 if (!tok_jmp("set")) {
133 strcpy(var
, tok_poptext());
134 def_set(var
, atoi(tok_poptext()));
140 static char *tok_font(int tok
, char *fn
)
144 if (tok
== T_LETTER
|| tok
== T_STRING
)
149 static void tok_expect(char *s
)
152 fprintf(stderr
, "neateqn: expected %s bot got %s\n",
158 static void eqn_pile(struct box
*box
, int sz0
, char *fn0
, int adj
)
160 struct box
*pile
[NPILES
] = {NULL
};
165 pile
[n
++] = box_alloc(sz0
, 0, box
->style
);
166 } while (!eqn_boxuntil(pile
[n
- 1], sz0
, fn0
, "above"));
168 box_pile(box
, pile
, adj
);
169 for (i
= 0; i
< n
; i
++)
173 static void eqn_matrix(struct box
*box
, int sz0
, char *fn0
)
175 struct box
*cols
[NPILES
][NPILES
] = {{NULL
}};
182 if (!tok_jmp("col") || !tok_jmp("ccol"))
184 else if (!tok_jmp("lcol"))
186 else if (!tok_jmp("rcol"))
193 cols
[ncols
][nrows
++] = box_alloc(sz0
, 0, box
->style
);
194 } while (!eqn_boxuntil(cols
[ncols
][nrows
- 1],
200 box_matrix(box
, ncols
, cols
, adj
);
201 for (i
= 0; i
< ncols
; i
++)
202 for (j
= 0; j
< NPILES
; j
++)
204 box_free(cols
[i
][j
]);
207 /* read a box without fractions */
208 static struct box
*eqn_left(int flg
, struct box
*pre
, int sz0
, char *fn0
)
210 struct box
*box
, *sqrt
, *inner
;
211 struct box
*sub_sub
= NULL
, *sub_sup
= NULL
;
212 struct box
*sub_from
= NULL
, *sub_to
= NULL
;
213 char left
[NMLEN
] = "", right
[NMLEN
] = "";
216 int newsz
= nregmk();
217 int subsz
= nregmk();
219 int style
= EQN_TSMASK
& flg
;
222 box
= box_alloc(sz0
, pre
? pre
->tcur
: 0, style
);
223 while (!eqn_commands(box
, sz
))
226 if (!tok_jmp("fat")) {
227 } else if (!tok_jmp("roman")) {
229 } else if (!tok_jmp("italic")) {
231 } else if (!tok_jmp("bold")) {
233 } else if (!tok_jmp("font")) {
234 strcpy(fn
, tok_poptext());
235 } else if (!tok_jmp("size")) {
236 sizeupdate(newsz
, sz
, tok_poptext());
238 } else if (!tok_jmp("fwd")) {
239 dx
+= atoi(tok_poptext());
240 } else if (!tok_jmp("back")) {
241 dx
-= atoi(tok_poptext());
242 } else if (!tok_jmp("down")) {
243 dy
+= atoi(tok_poptext());
244 } else if (!tok_jmp("up")) {
245 dy
-= atoi(tok_poptext());
252 if (!tok_jmp("sqrt")) {
253 sqrt
= eqn_left(style
, NULL
, sz
, fn
);
256 } else if (!tok_jmp("pile") || !tok_jmp("cpile")) {
257 eqn_pile(box
, sz
, fn
, 'c');
258 } else if (!tok_jmp("lpile")) {
259 eqn_pile(box
, sz
, fn
, 'l');
260 } else if (!tok_jmp("rpile")) {
261 eqn_pile(box
, sz
, fn
, 'r');
262 } else if (!tok_jmp("matrix")) {
263 eqn_matrix(box
, sz
, fn
);
264 } else if (!tok_jmp("vcenter")) {
265 inner
= eqn_left(flg
, pre
, sz
, fn
);
266 box_vcenter(box
, inner
);
268 } else if (!tok_jmp("{")) {
269 eqn_boxuntil(box
, sz
, fn
, "}");
270 } else if (!tok_jmp("left")) {
271 inner
= box_alloc(sz
, 0, style
);
272 snprintf(left
, sizeof(left
), "%s", tok_improve(tok_poptext()));
273 eqn_boxuntil(inner
, sz
, fn
, "right");
274 snprintf(right
, sizeof(right
), "%s", tok_improve(tok_poptext()));
275 printf(".ft %s\n", grfont
);
276 box_wrap(box
, inner
, left
[0] ? left
: NULL
,
277 right
[0] ? right
: NULL
);
280 box_move(box
, dy
, dx
);
281 box_putf(box
, "\\s%s", escarg(nreg(sz
)));
283 char *cfn
= tok_font(tok_type(), fn
);
284 box_puttext(box
, tok_type() | FN2(cfn
), "\\f%s%s",
285 escarg(cfn
), tok_improve(tok_get()));
287 } while (!tok_sep());
289 box_move(box
, -dy
, -dx
);
292 if (!tok_jmp("dyad")) {
293 printf(".ft %s\n", grfont
);
294 box_accent(box
, "\\(ab");
295 } else if (!tok_jmp("bar")) {
296 printf(".ft %s\n", grfont
);
298 } else if (!tok_jmp("under")) {
299 printf(".ft %s\n", grfont
);
301 } else if (!tok_jmp("vec")) {
302 printf(".ft %s\n", grfont
);
303 box_accent(box
, "\\s[\\n(.s/2]\\(->\\s0");
304 } else if (!tok_jmp("tilde")) {
305 printf(".ft %s\n", grfont
);
306 box_accent(box
, "\\s[\\n(.s*3/4]\\(ap\\s0");
307 } else if (!tok_jmp("hat")) {
308 printf(".ft %s\n", grfont
);
309 box_accent(box
, "ˆ");
310 } else if (!tok_jmp("dot")) {
311 printf(".ft %s\n", grfont
);
312 box_accent(box
, ".");
313 } else if (!tok_jmp("dotdot")) {
314 printf(".ft %s\n", grfont
);
315 box_accent(box
, "..");
320 if (!tok_jmp("sub")) {
321 sizesub(subsz
, sz0
, ts_sup(style
), style
);
322 sub_sub
= eqn_left(ts_sup(style
) | EQN_SUB
, NULL
, subsz
, fn0
);
324 if ((sub_sub
|| !(flg
& EQN_SUB
)) && !tok_jmp("sup")) {
325 sizesub(subsz
, sz0
, ts_sub(style
), style
);
326 sub_sup
= eqn_left(ts_sub(style
), NULL
, subsz
, fn0
);
328 if (sub_sub
|| sub_sup
)
329 box_sub(box
, sub_sub
, sub_sup
);
330 if (!tok_jmp("from")) {
331 sizesub(subsz
, sz0
, ts_sub(style
), style
);
332 sub_from
= eqn_left(ts_sub(style
) | EQN_FROM
, NULL
, subsz
, fn0
);
334 if ((sub_from
|| !(flg
& EQN_FROM
)) && !tok_jmp("to")) {
335 sizesub(subsz
, sz0
, ts_sup(style
), style
);
336 sub_to
= eqn_left(ts_sup(style
), NULL
, subsz
, fn0
);
338 if (sub_from
|| sub_to
) {
339 inner
= box_alloc(sz0
, 0, style
);
340 box_from(inner
, box
, sub_from
, sub_to
);
358 static struct box
*eqn_box(int flg
, struct box
*pre
, int sz0
, char *fn0
)
361 struct box
*sub_num
= NULL
, *sub_den
= NULL
;
362 int style
= flg
& EQN_TSMASK
;
363 box
= eqn_left(flg
, pre
, sz0
, fn0
);
364 while (!tok_jmp("over")) {
366 sub_den
= eqn_left(TS_MK(TS_SZ(style
), 1), NULL
, sz0
, fn0
);
367 box
= box_alloc(sz0
, pre
? pre
->tcur
: 0, style
);
368 printf(".ft %s\n", grfont
);
369 box_over(box
, sub_num
, sub_den
);
376 static struct box
*eqn_read(int style
)
378 struct box
*box
, *sub
;
379 int szreg
= nregmk();
380 printf(".nr %s %s\n", nregname(szreg
), gsize
);
381 box
= box_alloc(szreg
, 0, style
);
383 if (!tok_jmp("mark")) {
384 eqn_mk
= !eqn_mk
? 1 : eqn_mk
;
385 box_markpos(box
, EQNMK
);
388 if (!tok_jmp("lineup")) {
390 box_markpos(box
, nregname(eqn_lineupreg
));
391 sprintf(eqn_lineup
, "\\h'\\n%su-%su'",
392 escarg(EQNMK
), nreg(eqn_lineupreg
));
395 sub
= eqn_box(style
| EQN_TOP
, box
, szreg
, NULL
);
409 for (i
= 0; def_macros
[i
][0]; i
++)
410 in_define(def_macros
[i
][0], def_macros
[i
][1]);
415 printf(".nr %s \\n(.s\n", EQNSZ
);
416 printf(".nr %s \\n(.f\n", EQNFN
);
417 eqn_lineupreg
= nregmk();
418 box
= eqn_read(tok_inline() ? TS_T
: TS_D
);
419 printf(".nr MK %d\n", eqn_mk
);
420 if (!box_empty(box
)) {
421 sprintf(eqnblk
, "%s%s", eqn_lineup
, box_toreg(box
));
424 eqn_lineup
[0] = '\0';
425 nregrm(eqn_lineupreg
);