2011-03-30 12:46:40 +00:00
|
|
|
#include "a.h"
|
|
|
|
/*
|
|
|
|
* 8. Number Registers
|
|
|
|
* (Reg register implementation is also here.)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* \nx N
|
|
|
|
* \n(xx N
|
|
|
|
* \n+x N+=M
|
|
|
|
* \n-x N-=M
|
|
|
|
*
|
|
|
|
* .nr R ±N M
|
|
|
|
* .af R c
|
|
|
|
*
|
|
|
|
* formats
|
|
|
|
* 1 0, 1, 2, 3, ...
|
|
|
|
* 001 001, 002, 003, ...
|
|
|
|
* i 0, i, ii, iii, iv, v, ...
|
|
|
|
* I 0, I, II, III, IV, V, ...
|
|
|
|
* a 0, a, b, ..., aa, ab, ..., zz, aaa, ...
|
|
|
|
* A 0, A, B, ..., AA, AB, ..., ZZ, AAA, ...
|
|
|
|
*
|
|
|
|
* \gx \g(xx return format of number register
|
|
|
|
*
|
|
|
|
* .rr R
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct Reg Reg;
|
|
|
|
struct Reg
|
|
|
|
{
|
|
|
|
Reg *next;
|
|
|
|
Rune *name;
|
|
|
|
Rune *val;
|
|
|
|
Rune *fmt;
|
|
|
|
int inc;
|
|
|
|
};
|
|
|
|
|
|
|
|
Reg *dslist;
|
|
|
|
Reg *nrlist;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Define strings and numbers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
dsnr(Rune *name, Rune *val, Reg **l)
|
|
|
|
{
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
for(s = *l; s != nil; s = *l){
|
|
|
|
if(runestrcmp(s->name, name) == 0)
|
|
|
|
break;
|
|
|
|
l = &s->next;
|
|
|
|
}
|
|
|
|
if(val == nil){
|
|
|
|
if(s){
|
|
|
|
*l = s->next;
|
|
|
|
free(s->val);
|
|
|
|
free(s->fmt);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(s == nil){
|
|
|
|
s = emalloc(sizeof(Reg));
|
|
|
|
*l = s;
|
|
|
|
s->name = erunestrdup(name);
|
|
|
|
}else
|
|
|
|
free(s->val);
|
|
|
|
s->val = erunestrdup(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
getdsnr(Rune *name, Reg *list)
|
|
|
|
{
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
for(s=list; s; s=s->next)
|
|
|
|
if(runestrcmp(name, s->name) == 0)
|
|
|
|
return s->val;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ds(Rune *name, Rune *val)
|
|
|
|
{
|
|
|
|
dsnr(name, val, &dslist);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
as(Rune *name, Rune *val)
|
|
|
|
{
|
|
|
|
Rune *p, *q;
|
|
|
|
|
|
|
|
p = getds(name);
|
|
|
|
if(p == nil)
|
|
|
|
p = L("");
|
|
|
|
q = runemalloc(runestrlen(p)+runestrlen(val)+1);
|
|
|
|
runestrcpy(q, p);
|
|
|
|
runestrcat(q, val);
|
|
|
|
ds(name, q);
|
|
|
|
free(q);
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
getds(Rune *name)
|
|
|
|
{
|
|
|
|
return getdsnr(name, dslist);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
printds(int t)
|
|
|
|
{
|
|
|
|
int n, total;
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
for(s=dslist; s; s=s->next){
|
|
|
|
if(s->val)
|
|
|
|
n = runestrlen(s->val);
|
|
|
|
else
|
|
|
|
n = 0;
|
|
|
|
total += n;
|
|
|
|
if(!t)
|
|
|
|
fprint(2, "%S\t%d\n", s->name, n);
|
|
|
|
}
|
|
|
|
fprint(2, "total\t%d\n", total);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nr(Rune *name, int val)
|
|
|
|
{
|
|
|
|
Rune buf[20];
|
|
|
|
|
|
|
|
runesnprint(buf, nelem(buf), "%d", val);
|
|
|
|
_nr(name, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
af(Rune *name, Rune *fmt)
|
|
|
|
{
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
if(_getnr(name) == nil)
|
|
|
|
_nr(name, L("0"));
|
|
|
|
for(s=nrlist; s; s=s->next)
|
|
|
|
if(runestrcmp(s->name, name) == 0)
|
|
|
|
s->fmt = erunestrdup(fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
getaf(Rune *name)
|
|
|
|
{
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
for(s=nrlist; s; s=s->next)
|
|
|
|
if(runestrcmp(s->name, name) == 0)
|
|
|
|
return s->fmt;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
printnr(void)
|
|
|
|
{
|
|
|
|
Reg *r;
|
|
|
|
|
|
|
|
for(r=nrlist; r; r=r->next)
|
|
|
|
fprint(2, "%S %S %d\n", r->name, r->val, r->inc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some internal number registers are actually strings,
|
|
|
|
* so provide _ versions to get at them.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
_nr(Rune *name, Rune *val)
|
|
|
|
{
|
|
|
|
dsnr(name, val, &nrlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
_getnr(Rune *name)
|
|
|
|
{
|
|
|
|
return getdsnr(name, nrlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
getnr(Rune *name)
|
|
|
|
{
|
|
|
|
Rune *p;
|
|
|
|
|
|
|
|
p = _getnr(name);
|
|
|
|
if(p == nil)
|
|
|
|
return 0;
|
|
|
|
return eval(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* new register */
|
|
|
|
void
|
|
|
|
r_nr(int argc, Rune **argv)
|
|
|
|
{
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
if(argc < 2)
|
|
|
|
return;
|
|
|
|
if(argc < 3)
|
|
|
|
nr(argv[1], 0);
|
|
|
|
else{
|
|
|
|
if(argv[2][0] == '+')
|
|
|
|
nr(argv[1], getnr(argv[1])+eval(argv[2]+1));
|
|
|
|
else if(argv[2][0] == '-')
|
|
|
|
nr(argv[1], getnr(argv[1])-eval(argv[2]+1));
|
|
|
|
else
|
|
|
|
nr(argv[1], eval(argv[2]));
|
|
|
|
}
|
|
|
|
if(argc > 3){
|
|
|
|
for(s=nrlist; s; s=s->next)
|
|
|
|
if(runestrcmp(s->name, argv[1]) == 0)
|
|
|
|
s->inc = eval(argv[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* assign format */
|
|
|
|
void
|
|
|
|
r_af(int argc, Rune **argv)
|
|
|
|
{
|
|
|
|
USED(argc);
|
|
|
|
|
|
|
|
af(argv[1], argv[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove register */
|
|
|
|
void
|
|
|
|
r_rr(int argc, Rune **argv)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=1; i<argc; i++)
|
|
|
|
_nr(argv[i], nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fmt integer in base 26 */
|
|
|
|
void
|
|
|
|
alpha(Rune *buf, int n, int a)
|
|
|
|
{
|
|
|
|
int i, v;
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
for(v=n; v>0; v/=26)
|
|
|
|
i++;
|
|
|
|
if(i == 0)
|
|
|
|
i = 1;
|
|
|
|
buf[i] = 0;
|
|
|
|
while(i > 0){
|
|
|
|
buf[--i] = a+n%26;
|
|
|
|
n /= 26;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct romanv {
|
|
|
|
char *s;
|
|
|
|
int v;
|
|
|
|
} romanv[] =
|
|
|
|
{
|
|
|
|
"m", 1000,
|
|
|
|
"cm", 900,
|
|
|
|
"d", 500,
|
|
|
|
"cd", 400,
|
|
|
|
"c", 100,
|
|
|
|
"xc", 90,
|
|
|
|
"l", 50,
|
|
|
|
"xl", 40,
|
|
|
|
"x", 10,
|
|
|
|
"ix", 9,
|
|
|
|
"v", 5,
|
|
|
|
"iv", 4,
|
|
|
|
"i", 1
|
|
|
|
};
|
|
|
|
|
|
|
|
/* fmt integer in roman numerals! */
|
|
|
|
void
|
|
|
|
roman(Rune *buf, int n, int upper)
|
|
|
|
{
|
|
|
|
Rune *p;
|
|
|
|
char *q;
|
|
|
|
struct romanv *r;
|
|
|
|
|
|
|
|
if(upper)
|
|
|
|
upper = 'A' - 'a';
|
|
|
|
if(n >= 5000 || n <= 0){
|
|
|
|
runestrcpy(buf, L("-"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p = buf;
|
|
|
|
r = romanv;
|
|
|
|
while(n > 0){
|
|
|
|
while(n >= r->v){
|
|
|
|
for(q=r->s; *q; q++)
|
|
|
|
*p++ = *q + upper;
|
|
|
|
n -= r->v;
|
|
|
|
}
|
|
|
|
r++;
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Rune*
|
|
|
|
getname(void)
|
|
|
|
{
|
|
|
|
int i, c, cc;
|
|
|
|
static Rune buf[100];
|
|
|
|
|
|
|
|
/* XXX add [name] syntax as in groff */
|
|
|
|
c = getnext();
|
|
|
|
if(c < 0)
|
|
|
|
return L("");
|
|
|
|
if(c == '\n'){
|
|
|
|
warn("newline in name\n");
|
|
|
|
ungetnext(c);
|
|
|
|
return L("");
|
|
|
|
}
|
|
|
|
if(c == '['){
|
|
|
|
for(i=0; i<nelem(buf)-1; i++){
|
|
|
|
if((c = getrune()) < 0)
|
|
|
|
return L("");
|
|
|
|
if(c == ']'){
|
|
|
|
buf[i] = 0;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
buf[i] = c;
|
|
|
|
}
|
|
|
|
return L("");
|
|
|
|
}
|
|
|
|
if(c != '('){
|
|
|
|
buf[0] = c;
|
|
|
|
buf[1] = 0;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
c = getnext();
|
|
|
|
cc = getnext();
|
|
|
|
if(c < 0 || cc < 0)
|
|
|
|
return L("");
|
2015-06-13 18:58:56 +00:00
|
|
|
if(c == '\n' || cc == '\n'){
|
2011-03-30 12:46:40 +00:00
|
|
|
warn("newline in \\n");
|
|
|
|
ungetnext(cc);
|
|
|
|
if(c == '\n')
|
|
|
|
ungetnext(c);
|
|
|
|
}
|
|
|
|
buf[0] = c;
|
|
|
|
buf[1] = cc;
|
|
|
|
buf[2] = 0;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* \n - return number register */
|
|
|
|
int
|
|
|
|
e_n(void)
|
|
|
|
{
|
|
|
|
int inc, v, l;
|
|
|
|
Rune *name, *fmt, buf[100];
|
|
|
|
Reg *s;
|
|
|
|
|
|
|
|
inc = getnext();
|
|
|
|
if(inc < 0)
|
|
|
|
return -1;
|
|
|
|
if(inc != '+' && inc != '-'){
|
|
|
|
ungetnext(inc);
|
|
|
|
inc = 0;
|
|
|
|
}
|
|
|
|
name = getname();
|
|
|
|
if(_getnr(name) == nil)
|
|
|
|
_nr(name, L("0"));
|
|
|
|
for(s=nrlist; s; s=s->next){
|
|
|
|
if(runestrcmp(s->name, name) == 0){
|
|
|
|
if(s->fmt == nil && !inc && s->val[0]){
|
|
|
|
/* might be a string! */
|
|
|
|
pushinputstring(s->val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
v = eval(s->val);
|
|
|
|
if(inc){
|
|
|
|
if(inc == '+')
|
|
|
|
v += s->inc;
|
|
|
|
else
|
|
|
|
v -= s->inc;
|
|
|
|
runesnprint(buf, nelem(buf), "%d", v);
|
|
|
|
free(s->val);
|
|
|
|
s->val = erunestrdup(buf);
|
|
|
|
}
|
|
|
|
fmt = s->fmt;
|
|
|
|
if(fmt == nil)
|
|
|
|
fmt = L("1");
|
|
|
|
switch(fmt[0]){
|
|
|
|
case 'i':
|
|
|
|
case 'I':
|
|
|
|
roman(buf, v, fmt[0]=='I');
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
alpha(buf, v, fmt[0]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
l = runestrlen(fmt);
|
|
|
|
if(l == 0)
|
|
|
|
l = 1;
|
|
|
|
runesnprint(buf, sizeof buf, "%0*d", l, v);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pushinputstring(buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pushinputstring(L(""));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* \g - number register format */
|
|
|
|
int
|
|
|
|
e_g(void)
|
|
|
|
{
|
|
|
|
Rune *p;
|
|
|
|
|
|
|
|
p = getaf(getname());
|
|
|
|
if(p == nil)
|
|
|
|
p = L("1");
|
|
|
|
pushinputstring(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
r_pnr(int argc, Rune **argv)
|
|
|
|
{
|
|
|
|
USED(argc);
|
|
|
|
USED(argv);
|
|
|
|
printnr();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
t8init(void)
|
|
|
|
{
|
|
|
|
addreq(L("nr"), r_nr, -1);
|
|
|
|
addreq(L("af"), r_af, 2);
|
|
|
|
addreq(L("rr"), r_rr, -1);
|
|
|
|
addreq(L("pnr"), r_pnr, 0);
|
|
|
|
|
|
|
|
addesc('n', e_n, CopyMode|ArgMode|HtmlMode);
|
|
|
|
addesc('g', e_g, 0);
|
|
|
|
}
|
|
|
|
|