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.
This commit is contained in:
Roberto E. Vargas Caballero 2026-01-20 16:31:13 +01:00
parent 759ef4f504
commit c5bfe949dc
3 changed files with 85 additions and 23 deletions

13
bc.1
View File

@ -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

69
bc.y
View File

@ -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);

26
tests/0050-bc.sh Executable file
View File

@ -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