commit c5bfe949dca7001f5e1d456b0c6aebef8fbe07c8
parent 759ef4f504aec455083582f18431127d7cdf8e73
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date: Tue, 20 Jan 2026 16:31:13 +0100
bc: Add support for long names
As dc supports extended identifiers and we already had
the option -s in bc that modifies the standard behaviour
we can extend bc in the -s mode to support longer names.
The lower case restriction is maintained just for
simplicity but it is possible to extend bc to support
full utf8 identifers.
Diffstat:
| M | bc.1 | | | 13 | +++++++++++-- |
| M | bc.y | | | 69 | ++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
| A | tests/0050-bc.sh | | | 26 | ++++++++++++++++++++++++++ |
3 files changed, 85 insertions(+), 23 deletions(-)
diff --git a/bc.1 b/bc.1
@@ -41,10 +41,19 @@ Enable yacc parser debugging output.
Load the mathematical library
that is loaded before any file from the command line.
.It Fl s
-Suppresses the automatic printing of expression results.
-In this mode, only explicit
+Enable the extended mode.
+In this mode,
+the automatic printing of expression results is suppressed,
+and only explicit
.Ic print
statements produce output.
+Names of variables and functions can be longer than 1 character,
+but still constrained to lower case latin characters.
+The output of
+.Ar bc
+in this mode is suitable only for the suckless
+.Ar dc
+version.
.El
.Sh LANGUAGE
.Ss Comments
diff --git a/bc.y b/bc.y
@@ -26,6 +26,7 @@ typedef struct macro Macro;
struct macro {
int op;
int id;
+ char *name;
int flowid;
int nested;
};
@@ -348,6 +349,7 @@ macro(int op)
d = ¯os[nested];
d->op = op;
d->nested = nested++;
+ d->name = NULL;
switch (op) {
case HOME:
@@ -359,6 +361,7 @@ macro(int op)
unwind = estrdup("");
inhome = 0;
d->id = funid(yytext);
+ d->name = estrdup(yytext);
d->flowid = macros[0].flowid;
break;
default:
@@ -417,17 +420,26 @@ funcode(Macro *d, char *params, char *vars, char *body)
{
char *s;
- s = code("[%s%s%s%s]s%c",
- vars, params,
- body,
- retcode(code(" 0")),
- d->id);
+ if (strlen(d->name) > 1) {
+ s = code("[%s%s%s%s]s\"()%s\"",
+ vars, params,
+ body,
+ retcode(code(" 0")),
+ d->name);
+ } else {
+ s = code(sflag ? "[%s%s%s%s]s<%d>" : "[%s%s%s%s]s%c",
+ vars, params,
+ body,
+ retcode(code(" 0")),
+ d->id);
+ free(d->name);
+ }
+
free(unwind);
unwind = NULL;
nested--;
inhome = 0;
-
return s;
}
@@ -448,14 +460,17 @@ forcode(Macro *d, char *init, char *cmp, char *inc, char *body)
{
char *s;
- s = code("[%s%ss.%s%c]s%c",
+ s = code(sflag ? "[%s%ss.%s<%d>]s<%d>" : "[%s%ss.%s%c]s%c",
body,
inc,
estrdup(cmp),
d->id, d->id);
writeout(s);
- s = code("%ss.%s%c ", init, cmp, d->id);
+ s = code(sflag ? "%ss.%s<%d> " : "%ss.%s%c ",
+ init,
+ cmp,
+ d->id);
nested--;
return s;
@@ -466,13 +481,14 @@ whilecode(Macro *d, char *cmp, char *body)
{
char *s;
- s = code("[%s%s%c]s%c",
+ s = code(sflag ? "[%s%s<%d>]s<%d>" : "[%s%s%c]s%c",
body,
estrdup(cmp),
d->id, d->id);
writeout(s);
- s = code("%s%c ", cmp, d->id);
+ s = code(sflag ? "%s<%d> " : "%s%c ",
+ cmp, d->id);
nested--;
return s;
@@ -483,10 +499,12 @@ ifcode(Macro *d, char *cmp, char *body)
{
char *s;
- s = code("[%s]s%c", body, d->id);
+ s = code(sflag ? "[%s]s<%d>" : "[%s]s%c",
+ body, d->id);
writeout(s);
- s = code("%s%c ", cmp, d->id);
+ s = code(sflag ? "%s<%d> " : "%s%c ",
+ cmp, d->id);
nested--;
return s;
@@ -505,19 +523,25 @@ retcode(char *expr)
static char *
ary(char *s)
{
- return code("%c", toupper(s[0]));
+ if (strlen(s) == 1)
+ return code("%c", toupper(s[0]));
+ return code("\"[]%s\"", estrdup(s));
}
static char *
ftn(char *s)
{
- return code("%c", funid(s));
+ if (strlen(s) == 1)
+ return code(sflag ? "<%d>" : "%c", funid(s));
+ return code("\"()%s\"", estrdup(s));
}
static char *
var(char *s)
{
- return code(s);
+ if (strlen(s) == 1)
+ return code(s);
+ return code("\"%s\"", estrdup(s));
}
static void
@@ -531,7 +555,7 @@ skipspaces(void)
{
int ch;
- while (isspace(ch = getc(filep))) {
+ while (isascii(ch = getc(filep)) && isspace(ch)) {
if (ch == '\n') {
lineno++;
break;
@@ -569,7 +593,7 @@ iden(int ch)
ungetc(ch, filep);
for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
ch = getc(filep);
- if (!islower(ch))
+ if (!isascii || !islower(ch))
break;
*bp = ch;
}
@@ -586,11 +610,13 @@ iden(int ch)
for (p = keywords; p->str && strcmp(p->str, yytext); ++p)
;
+ if (p->str)
+ return p->token;
- if (!p->str)
+ if (!sflag)
yyerror("invalid keyword");
-
- return p->token;
+ strcpy(yylval.id, yytext);
+ return ID;
}
static char *
@@ -785,6 +811,7 @@ static void
spawn(void)
{
int fds[2];
+ char *par = sflag ? "-i" : NULL;
char errmsg[] = "bc:error execing dc\n";
if (pipe(fds) < 0)
@@ -804,7 +831,7 @@ spawn(void)
dup(fds[0]);
close(fds[0]);
close(fds[1]);
- execlp(dcprog, "dc", (char *) NULL);
+ execlp(dcprog, "dc", par, (char *) NULL);
/* it shouldn't happen */
write(3, errmsg, sizeof(errmsg)-1);
diff --git a/tests/0050-bc.sh b/tests/0050-bc.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+tmp=$$.tmp
+
+trap 'rm -f $tmp' EXIT
+trap 'exit $?' HUP INT TERM
+
+cat <<'EOF' > $tmp
+par=1
+inc=4
+EOF
+
+$EXEC ../bc -sp ../dc <<'EOF' | diff -u - $tmp
+define alpha(par, inc) {
+ auto cnt
+
+ par = par + 1
+ cnt = par + inc
+ return (cnt)
+}
+
+par = 1
+inc = alpha(par, 2)
+print "par=",par
+print "inc=",inc
+EOF