sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

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:
Mbc.1 | 13+++++++++++--
Mbc.y | 69++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Atests/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 = &macros[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