version 1.19, 2003/11/17 11:20:13 |
version 1.20, 2003/12/02 09:00:07 |
|
|
#include <ctype.h> |
#include <ctype.h> |
#include <err.h> |
#include <err.h> |
#include <limits.h> |
#include <limits.h> |
|
#include <search.h> |
#include <signal.h> |
#include <signal.h> |
#include <stdarg.h> |
#include <stdarg.h> |
#include <stdbool.h> |
#include <stdbool.h> |
|
|
static void emit_macro(int, ssize_t); |
static void emit_macro(int, ssize_t); |
static void free_tree(void); |
static void free_tree(void); |
static ssize_t numnode(int); |
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_par(ssize_t); |
static void add_local(ssize_t); |
static void add_local(ssize_t); |
static void warning(const char *); |
static void warning(const char *); |
|
|
static char **sargv; |
static char **sargv; |
static char *filename; |
static char *filename; |
static bool do_fork = true; |
static bool do_fork = true; |
|
static u_short var_count; |
|
|
extern char *__progname; |
extern char *__progname; |
|
|
#define BREAKSTACK_SZ (sizeof(breakstack)/sizeof(breakstack[0])) |
#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 FUNC_CHAR 0x01 |
#define ARRAY_CHAR 0xa1 |
#define ARRAY_CHAR 0xa1 |
|
|
#define LETTER_NODE(str) (cs(str_table[(int)str[0]])) |
/* Skip '\0', [, \ and ] */ |
#define ARRAY_NODE(str) (cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR])) |
#define ENCODE(c) ((c) < '[' ? (c) : (c) + 3); |
#define FUNCTION_NODE(str) (cs(str_table[(int)str[0] - 'a' + FUNC_CHAR])) |
#define VAR_BASE (256-4) |
|
#define MAX_VARIABLES (VAR_BASE * VAR_BASE) |
|
|
%} |
%} |
|
|
|
|
ssize_t node; |
ssize_t node; |
struct lvalue lvalue; |
struct lvalue lvalue; |
const char *str; |
const char *str; |
|
char *astr; |
} |
} |
|
|
%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT |
%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT |
%token NEWLINE |
%token NEWLINE |
%token <str> LETTER NUMBER STRING |
%token <astr> LETTER |
|
%token <str> NUMBER STRING |
%token DEFINE BREAK QUIT LENGTH |
%token DEFINE BREAK QUIT LENGTH |
%token RETURN FOR IF WHILE SQRT |
%token RETURN FOR IF WHILE SQRT |
%token SCALE IBASE OBASE AUTO |
%token SCALE IBASE OBASE AUTO |
|
|
%% |
%% |
|
|
program : /* empty */ |
program : /* empty */ |
{ |
| program input_item |
putchar('q'); |
|
fflush(stdout); |
|
exit(0); |
|
} |
|
| input_item program |
|
; |
; |
|
|
input_item : semicolon_list NEWLINE |
input_item : semicolon_list NEWLINE |
|
|
macro_char = '{'; |
macro_char = '{'; |
else if (macro_char == ARRAY_CHAR) |
else if (macro_char == ARRAY_CHAR) |
macro_char += 26; |
macro_char += 26; |
else if (macro_char == 256) |
else if (macro_char == 255) |
fatal("program too big"); |
fatal("program too big"); |
if (breaksp == BREAKSTACK_SZ) |
if (breaksp == BREAKSTACK_SZ) |
fatal("nesting too deep"); |
fatal("nesting too deep"); |
|
|
|
|
function_header : DEFINE LETTER LPAR |
function_header : DEFINE LETTER LPAR |
{ |
{ |
$$ = FUNCTION_NODE($2); |
$$ = function_node($2); |
|
free($2); |
prologue = cs(""); |
prologue = cs(""); |
epilogue = cs(""); |
epilogue = cs(""); |
nesting = 1; |
nesting = 1; |
|
|
|
|
parameter_list : LETTER |
parameter_list : LETTER |
{ |
{ |
add_par(LETTER_NODE($1)); |
add_par(letter_node($1)); |
|
free($1); |
} |
} |
| LETTER LBRACKET RBRACKET |
| LETTER LBRACKET RBRACKET |
{ |
{ |
add_par(ARRAY_NODE($1)); |
add_par(array_node($1)); |
|
free($1); |
} |
} |
| parameter_list COMMA LETTER |
| parameter_list COMMA LETTER |
{ |
{ |
add_par(LETTER_NODE($3)); |
add_par(letter_node($3)); |
|
free($3); |
} |
} |
| parameter_list COMMA LETTER LBRACKET RBRACKET |
| parameter_list COMMA LETTER LBRACKET RBRACKET |
{ |
{ |
add_par(ARRAY_NODE($3)); |
add_par(array_node($3)); |
|
free($3); |
} |
} |
; |
; |
|
|
|
|
|
|
define_list : LETTER |
define_list : LETTER |
{ |
{ |
add_local(LETTER_NODE($1)); |
add_local(letter_node($1)); |
|
free($1); |
} |
} |
| LETTER LBRACKET RBRACKET |
| LETTER LBRACKET RBRACKET |
{ |
{ |
add_local(ARRAY_NODE($1)); |
add_local(array_node($1)); |
|
free($1); |
} |
} |
| define_list COMMA LETTER |
| define_list COMMA LETTER |
{ |
{ |
add_local(LETTER_NODE($3)); |
add_local(letter_node($3)); |
|
free($3); |
} |
} |
| define_list COMMA LETTER LBRACKET RBRACKET |
| define_list COMMA LETTER LBRACKET RBRACKET |
{ |
{ |
add_local(ARRAY_NODE($3)); |
add_local(array_node($3)); |
|
free($3); |
} |
} |
; |
; |
|
|
|
|
} |
} |
| argument_list COMMA LETTER LBRACKET RBRACKET |
| argument_list COMMA LETTER LBRACKET RBRACKET |
{ |
{ |
$$ = node($1, cs("l"), ARRAY_NODE($3), |
$$ = node($1, cs("l"), array_node($3), |
END_NODE); |
END_NODE); |
|
free($3); |
} |
} |
; |
; |
|
|
|
|
| LETTER LPAR opt_argument_list RPAR |
| LETTER LPAR opt_argument_list RPAR |
{ |
{ |
$$ = node($3, cs("l"), |
$$ = node($3, cs("l"), |
FUNCTION_NODE($1), cs("x"), |
function_node($1), cs("x"), |
END_NODE); |
END_NODE); |
|
free($1); |
} |
} |
| MINUS expression %prec UMINUS |
| MINUS expression %prec UMINUS |
{ |
{ |
|
|
named_expression |
named_expression |
: LETTER |
: LETTER |
{ |
{ |
$$.load = node(cs("l"), LETTER_NODE($1), |
$$.load = node(cs("l"), letter_node($1), |
END_NODE); |
END_NODE); |
$$.store = node(cs("s"), LETTER_NODE($1), |
$$.store = node(cs("s"), letter_node($1), |
END_NODE); |
END_NODE); |
|
free($1); |
} |
} |
| LETTER LBRACKET expression RBRACKET |
| LETTER LBRACKET expression RBRACKET |
{ |
{ |
$$.load = node($3, cs(";"), |
$$.load = node($3, cs(";"), |
ARRAY_NODE($1), END_NODE); |
array_node($1), END_NODE); |
$$.store = node($3, cs(":"), |
$$.store = node($3, cs(":"), |
ARRAY_NODE($1), END_NODE); |
array_node($1), END_NODE); |
|
free($1); |
} |
} |
| SCALE |
| SCALE |
{ |
{ |
|
|
else if (num < 16) |
else if (num < 16) |
p = str_table['A' - 10 + num]; |
p = str_table['A' - 10 + num]; |
else |
else |
err(1, "internal error: break num > 15"); |
errx(1, "internal error: break num > 15"); |
return node(cs(" "), cs(p), END_NODE); |
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 |
static void |
add_par(ssize_t n) |
add_par(ssize_t n) |
{ |
{ |
|
|
str_table[i][0] = i; |
str_table[i][0] = i; |
str_table[i][1] = '\0'; |
str_table[i][1] = '\0'; |
} |
} |
|
if (hcreate(1 << 16) == 0) |
|
err(1, NULL); |
} |
} |
|
|
|
|
|
|
dup(p[0]); |
dup(p[0]); |
close(p[0]); |
close(p[0]); |
close(p[1]); |
close(p[1]); |
execl(_PATH_DC, "dc", "-", (char *)NULL); |
execl(_PATH_DC, "dc", "-x", (char *)NULL); |
err(1, "cannot find dc"); |
err(1, "cannot find dc"); |
} |
} |
} |
} |