summaryrefslogtreecommitdiff
path: root/usr.bin/bc
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2003-12-02 09:00:08 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2003-12-02 09:00:08 +0000
commite0fb05eb8bc64b3760a73c307816506bb4d6239e (patch)
tree660a36b681281108acf476f6b80933e15fb73721 /usr.bin/bc
parent951fa8ed01f4c8bc666f456c77717ee2ea583369 (diff)
o Introduce long variable names, a non-portable extension.
o Make main program target left recursive. Reduces parse stack usage, making it possible to compile programs > 10000 lines.
Diffstat (limited to 'usr.bin/bc')
-rw-r--r--usr.bin/bc/bc.y156
-rw-r--r--usr.bin/bc/extern.h6
-rw-r--r--usr.bin/bc/scan.l20
3 files changed, 144 insertions, 38 deletions
diff --git a/usr.bin/bc/bc.y b/usr.bin/bc/bc.y
index 0d89209b3fb..5db40742c5b 100644
--- a/usr.bin/bc/bc.y
+++ b/usr.bin/bc/bc.y
@@ -1,5 +1,5 @@
%{
-/* $OpenBSD: bc.y,v 1.19 2003/11/17 11:20:13 otto Exp $ */
+/* $OpenBSD: bc.y,v 1.20 2003/12/02 09:00:07 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
@@ -31,12 +31,13 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: bc.y,v 1.19 2003/11/17 11:20:13 otto Exp $";
+static const char rcsid[] = "$OpenBSD: bc.y,v 1.20 2003/12/02 09:00:07 otto Exp $";
#endif /* not lint */
#include <ctype.h>
#include <err.h>
#include <limits.h>
+#include <search.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -69,6 +70,11 @@ static void emit(ssize_t);
static void emit_macro(int, ssize_t);
static void free_tree(void);
static ssize_t numnode(int);
+static ssize_t lookup(char *, size_t, char);
+static ssize_t letter_node(char *);
+static ssize_t array_node(char *);
+static ssize_t function_node(char *);
+
static void add_par(ssize_t);
static void add_local(ssize_t);
static void warning(const char *);
@@ -92,18 +98,20 @@ static int sargc;
static char **sargv;
static char *filename;
static bool do_fork = true;
+static u_short var_count;
extern char *__progname;
#define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0]))
-/* These values are 4.4BSD dc compatible */
+/* These values are 4.4BSD bc compatible */
#define FUNC_CHAR 0x01
#define ARRAY_CHAR 0xa1
-#define LETTER_NODE(str) (cs(str_table[(int)str[0]]))
-#define ARRAY_NODE(str) (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]))
-#define FUNCTION_NODE(str) (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]))
+/* Skip '\0', [, \ and ] */
+#define ENCODE(c) ((c) < '[' ? (c) : (c) + 3);
+#define VAR_BASE (256-4)
+#define MAX_VARIABLES (VAR_BASE * VAR_BASE)
%}
@@ -113,11 +121,13 @@ extern char *__progname;
ssize_t node;
struct lvalue lvalue;
const char *str;
+ char *astr;
}
%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
%token NEWLINE
-%token <str> LETTER NUMBER STRING
+%token <astr> LETTER
+%token <str> NUMBER STRING
%token DEFINE BREAK QUIT LENGTH
%token RETURN FOR IF WHILE SQRT
%token SCALE IBASE OBASE AUTO
@@ -156,12 +166,7 @@ extern char *__progname;
%%
program : /* empty */
- {
- putchar('q');
- fflush(stdout);
- exit(0);
- }
- | input_item program
+ | program input_item
;
input_item : semicolon_list NEWLINE
@@ -342,7 +347,7 @@ alloc_macro : /* empty */
macro_char = '{';
else if (macro_char == ARRAY_CHAR)
macro_char += 26;
- else if (macro_char == 256)
+ else if (macro_char == 255)
fatal("program too big");
if (breaksp == BREAKSTACK_SZ)
fatal("nesting too deep");
@@ -372,7 +377,8 @@ function : function_header opt_parameter_list RPAR opt_newline
function_header : DEFINE LETTER LPAR
{
- $$ = FUNCTION_NODE($2);
+ $$ = function_node($2);
+ free($2);
prologue = cs("");
epilogue = cs("");
nesting = 1;
@@ -393,19 +399,23 @@ opt_parameter_list
parameter_list : LETTER
{
- add_par(LETTER_NODE($1));
+ add_par(letter_node($1));
+ free($1);
}
| LETTER LBRACKET RBRACKET
{
- add_par(ARRAY_NODE($1));
+ add_par(array_node($1));
+ free($1);
}
| parameter_list COMMA LETTER
{
- add_par(LETTER_NODE($3));
+ add_par(letter_node($3));
+ free($3);
}
| parameter_list COMMA LETTER LBRACKET RBRACKET
{
- add_par(ARRAY_NODE($3));
+ add_par(array_node($3));
+ free($3);
}
;
@@ -420,19 +430,23 @@ opt_auto_define_list
define_list : LETTER
{
- add_local(LETTER_NODE($1));
+ add_local(letter_node($1));
+ free($1);
}
| LETTER LBRACKET RBRACKET
{
- add_local(ARRAY_NODE($1));
+ add_local(array_node($1));
+ free($1);
}
| define_list COMMA LETTER
{
- add_local(LETTER_NODE($3));
+ add_local(letter_node($3));
+ free($3);
}
| define_list COMMA LETTER LBRACKET RBRACKET
{
- add_local(ARRAY_NODE($3));
+ add_local(array_node($3));
+ free($3);
}
;
@@ -453,8 +467,9 @@ argument_list : expression
}
| argument_list COMMA LETTER LBRACKET RBRACKET
{
- $$ = node($1, cs("l"), ARRAY_NODE($3),
+ $$ = node($1, cs("l"), array_node($3),
END_NODE);
+ free($3);
}
;
@@ -542,8 +557,9 @@ expression : named_expression
| LETTER LPAR opt_argument_list RPAR
{
$$ = node($3, cs("l"),
- FUNCTION_NODE($1), cs("x"),
+ function_node($1), cs("x"),
END_NODE);
+ free($1);
}
| MINUS expression %prec UMINUS
{
@@ -660,17 +676,19 @@ expression : named_expression
named_expression
: LETTER
{
- $$.load = node(cs("l"), LETTER_NODE($1),
+ $$.load = node(cs("l"), letter_node($1),
END_NODE);
- $$.store = node(cs("s"), LETTER_NODE($1),
+ $$.store = node(cs("s"), letter_node($1),
END_NODE);
+ free($1);
}
| LETTER LBRACKET expression RBRACKET
{
$$.load = node($3, cs(";"),
- ARRAY_NODE($1), END_NODE);
+ array_node($1), END_NODE);
$$.store = node($3, cs(":"),
- ARRAY_NODE($1), END_NODE);
+ array_node($1), END_NODE);
+ free($1);
}
| SCALE
{
@@ -810,10 +828,84 @@ numnode(int num)
else if (num < 16)
p = str_table['A' - 10 + num];
else
- err(1, "internal error: break num > 15");
+ errx(1, "internal error: break num > 15");
return node(cs(" "), cs(p), END_NODE);
}
+
+static ssize_t
+lookup(char * str, size_t len, char type)
+{
+ ENTRY entry, *found;
+ u_short num;
+ u_char *p;
+
+ /* The scanner allocated an extra byte already */
+ if (str[len-1] != type) {
+ str[len] = type;
+ str[len+1] = '\0';
+ }
+ entry.key = str;
+ found = hsearch(entry, FIND);
+ if (found == NULL) {
+ if (var_count == MAX_VARIABLES)
+ errx(1, "too many variables");
+ p = malloc(4);
+ if (p == NULL)
+ err(1, NULL);
+ num = var_count++;
+ p[0] = 255;
+ p[1] = ENCODE(num / VAR_BASE + 1);
+ p[2] = ENCODE(num % VAR_BASE + 1);
+ p[3] = '\0';
+
+ entry.data = p;
+ entry.key = strdup(str);
+ if (entry.key == NULL)
+ err(1, NULL);
+ found = hsearch(entry, ENTER);
+ if (found == NULL)
+ err(1, NULL);
+ }
+ return cs(found->data);
+}
+
+static ssize_t
+letter_node(char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ if (len == 1 && str[0] != '_')
+ return cs(str_table[(int)str[0]]);
+ else
+ return lookup(str, len, 'L');
+}
+
+static ssize_t
+array_node(char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ if (len == 1 && str[0] != '_')
+ return cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]);
+ else
+ return lookup(str, len, 'A');
+}
+
+static ssize_t
+function_node(char *str)
+{
+ size_t len;
+
+ len = strlen(str);
+ if (len == 1 && str[0] != '_')
+ return cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]);
+ else
+ return lookup(str, len, 'F');
+}
+
static void
add_par(ssize_t n)
{
@@ -893,6 +985,8 @@ init(void)
str_table[i][0] = i;
str_table[i][1] = '\0';
}
+ if (hcreate(1 << 16) == 0)
+ err(1, NULL);
}
@@ -1003,7 +1097,7 @@ main(int argc, char *argv[])
dup(p[0]);
close(p[0]);
close(p[1]);
- execl(_PATH_DC, "dc", "-", (char *)NULL);
+ execl(_PATH_DC, "dc", "-x", (char *)NULL);
err(1, "cannot find dc");
}
}
diff --git a/usr.bin/bc/extern.h b/usr.bin/bc/extern.h
index 8d4b0417523..cc99d12adfa 100644
--- a/usr.bin/bc/extern.h
+++ b/usr.bin/bc/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.3 2003/09/28 07:57:57 otto Exp $ */
+/* $OpenBSD: extern.h,v 1.4 2003/12/02 09:00:07 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
@@ -19,8 +19,8 @@
#include <stdio.h>
struct lvalue {
- int load;
- int store;
+ ssize_t load;
+ ssize_t store;
};
int yylex(void);
diff --git a/usr.bin/bc/scan.l b/usr.bin/bc/scan.l
index 5bedbef2299..1e8a3ebaf13 100644
--- a/usr.bin/bc/scan.l
+++ b/usr.bin/bc/scan.l
@@ -1,5 +1,5 @@
%{
-/* $OpenBSD: scan.l,v 1.13 2003/11/17 11:20:13 otto Exp $ */
+/* $OpenBSD: scan.l,v 1.14 2003/12/02 09:00:07 otto Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
@@ -18,7 +18,7 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: scan.l,v 1.13 2003/11/17 11:20:13 otto Exp $";
+static const char rcsid[] = "$OpenBSD: scan.l,v 1.14 2003/12/02 09:00:07 otto Exp $";
#endif /* not lint */
#include <err.h>
@@ -40,6 +40,9 @@ static void add_str(const char *);
%}
DIGIT [0-9A-F]
+ALPHA [a-z_]
+ALPHANUM [a-z_0-9]
+
%x comment string number
%%
@@ -162,13 +165,22 @@ DIGIT [0-9A-F]
"{" return LBRACE;
"}" return RBRACE;
-[a-z] yylval.str = yytext; return LETTER;
+{ALPHA}{ALPHANUM}* {
+ /* alloc an extra byte for the type marker */
+ char *p = malloc(yyleng + 2);
+ if (p == NULL)
+ err(1, NULL);
+ strlcpy(p, yytext, yyleng + 1);
+ yylval.astr = p;
+ return LETTER;
+ }
\\\n lineno++;
\n lineno++; return NEWLINE;
#[^\n]* ;
[ \t] ;
+<<EOF>> return QUIT;
. yyerror("illegal character");
%%
@@ -191,7 +203,7 @@ add_str(const char *str)
arglen = strlen(str);
- if (strlen(strbuf) + arglen + 1> strbuf_sz) {
+ if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
size_t newsize;
char *p;