diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-02-10 14:08:36 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-02-10 14:08:36 +0000 |
commit | a1871918823166cac9f0c12164ba27cb3b1f0c2c (patch) | |
tree | 7260d118aa5af6a8f006f9b2dac6cabde782db8c /mfd/drivers.c | |
parent | 455b645247bdc0f01239b2352a9d8f07f446024f (diff) | |
download | mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.gz mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.bz2 |
Merged HEAD from branches/gmach
git-svn-id: file:///svnroot/mailfromd/trunk@1612 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'mfd/drivers.c')
-rw-r--r-- | mfd/drivers.c | 2308 |
1 files changed, 2308 insertions, 0 deletions
diff --git a/mfd/drivers.c b/mfd/drivers.c new file mode 100644 index 00000000..0d4bb601 --- /dev/null +++ b/mfd/drivers.c @@ -0,0 +1,2308 @@ +/* This file is part of Mailfromd. + Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define MARK_LOCUS() \ + do if (!*old_locus || !LOCUS_EQ(*old_locus, &node->locus)) { \ + struct literal *lit = literal_lookup(node->locus.file); \ + *old_locus = &node->locus; \ + code_op(opcode_locus); \ + code_immediate((void*)lit->off); \ + code_immediate((void*)node->locus.line); \ + } while (0) + + + +void +code_memref(NODE *node) +{ + switch (node->v.var_ref.variable->storage_class) { + case storage_extern: + code_op(opcode_push); + code_immediate((void*)node->v.var_ref.variable->off); + break; + + case storage_auto: + code_op(opcode_memstk); + code_immediate((void*)node->v.var_ref.nframes); + code_immediate((void*)-node->v.var_ref.variable->off); + break; + + case storage_param: + code_op(opcode_memstk); + code_immediate((void*)node->v.var_ref.nframes); + code_immediate((void*)(node->v.var_ref.variable->off + 2)); + break; + } +} + + +/* type noop */ +/* Empty node, nothing to print, mark, optimize or code */ + + +/* type string */ + +void +print_type_string(NODE *node, int level) +{ + print_level(level); + printf("STRING: \""); + print_quoted_string(node->v.literal->text); + printf("\"\n"); +} + +void +mark_type_string(NODE *node) +{ + node->v.literal->flags |= VAR_REFERENCED; +} + +void +code_type_string(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + code_op(opcode_push); + code_immediate((const void*)node->v.literal->off); +} + + +/* type symbol */ + +void +print_type_symbol(NODE *node, int level) +{ + print_level(level); + printf("SYMBOL: %s\n", node->v.literal->text); +} + +void +code_type_symbol(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + code_op(opcode_symbol); + code_immediate((void*)node->v.literal->off); +} + +void +mark_type_symbol(NODE *node) +{ + node->v.literal->flags |= VAR_REFERENCED; +} + + +/* type number */ +void +print_type_number(NODE *node, int level) +{ + print_level(level); + printf("NUMBER: %ld\n", node->v.number); +} + +void +code_type_number(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + code_op(opcode_push); + code_immediate((void*)node->v.number); +} + + +/* type if */ + +void +print_type_if(NODE *node, int level) +{ + print_level(level); + printf("COND: \n"); + print_node(node->v.cond.cond, level); + print_level(level); + printf("IFTRUE\n"); + print_node_list(node->v.cond.if_true, level+1); + print_level(level); + printf("IFFALSE\n"); + print_node_list(node->v.cond.if_false, level+1); +} + +void +mark_type_if(NODE *node) +{ + mark(node->v.cond.cond); + mark(node->v.cond.if_true); + mark(node->v.cond.if_false); +} + +void +optimize_type_if(NODE *node) +{ + NODE *p = node->v.cond.cond; + optimize(p); + optimize(node->v.cond.if_true); + optimize(node->v.cond.if_false); + if (p->type == node_type_number) { + NODE *head; + NODE *tail = node->next; + if (p->v.number) { + head = node->v.cond.if_true; + free_subtree(node->v.cond.if_false); + } else { + head = node->v.cond.if_false; + free_subtree(node->v.cond.if_true); + } + + if (head) { + *node = *head; + free_node(head); + + for (; node->next; node = node->next) + ; + node->next = tail; + } else + node->type = node_type_noop; + } else if (p->type == node_type_string) { + NODE *head; + NODE *tail = p->next; + if (p->v.literal->text[0]) { + head = node->v.cond.if_true; + free_subtree(node->v.cond.if_false); + } else { + head = node->v.cond.if_false; + free_subtree(node->v.cond.if_true); + } + + if (head) { + *node = *head; + free_node(head); + + for (; node->next; node = node->next) + ; + node->next = tail; + } else + node->type = node_type_noop; + } +} + +void +code_type_if(NODE *node, struct locus **old_locus) +{ + prog_counter_t pos1, pos2, endpos; + + code_node(node->v.cond.cond); + MARK_LOCUS(); + code_op(opcode_bz); + pos1 = code_immediate(NULL); + traverse_tree(node->v.cond.if_true); + if (node->v.cond.if_false) { + code_op(opcode_jmp); + pos2 = code_immediate(NULL); + traverse_tree(node->v.cond.if_false); + endpos = code_get_counter (); + code_put(pos1, (void *)(pos2 - pos1)); + code_put(pos2, (void *)(endpos - pos2 - 1)); + } else + code_put(pos1, (void *)(code_get_counter () - pos1 - 1)); +} + + +/* type bin */ + +void +print_type_bin(NODE *node, int level) +{ + print_level(level); + print_bin_op(node->v.bin.opcode); + if (node->v.bin.opcode == bin_match + || node->v.bin.opcode == bin_fnmatch) { + if (node->v.bin.qualifier & QUALIFIER_MX) + printf(",MX"); + } + printf("\n"); + print_node(node->v.bin.arg[0], level+1); + print_node(node->v.bin.arg[1], level+1); +} + +void +mark_type_bin(NODE *node) +{ + mark(node->v.bin.arg[0]); + mark(node->v.bin.arg[1]); +} + +static void +optimize_arith(NODE *node) +{ + NODE *arg0 = node->v.bin.arg[0]; + NODE *arg1 = node->v.bin.arg[1]; + + if (arg0->type == node_type_number + && arg1->type == node_type_number) { + switch (node->v.bin.opcode) { + case bin_add: + node->v.number = arg0->v.number + arg1->v.number; + break; + + case bin_sub: + node->v.number = arg0->v.number - arg1->v.number; + break; + + case bin_mul: + node->v.number = arg0->v.number * arg1->v.number; + break; + + case bin_div: + if (arg1->v.number == 0) { + parse_error_locus(&node->locus, + _("division by zero")); + break; + } + node->v.number = arg0->v.number / arg1->v.number; + break; + + case bin_logand: + node->v.number = arg0->v.number & arg1->v.number; + break; + + case bin_logor: + node->v.number = arg0->v.number | arg1->v.number; + break; + + case bin_logxor: + node->v.number = arg0->v.number ^ arg1->v.number; + break; + + default: + return; + } + node->type = node_type_number; + free_node(arg0); + free_node(arg1); + } else if (node_type(arg0) != dtype_number) { + parse_error_locus(&arg0->locus, + _("left-hand side argument to the " + "arithmetical operation is " + "of wrong data type")); + } else if (node_type(arg1) != dtype_number) { + parse_error_locus(&arg1->locus, + _("right-hand side argument to the " + "arithmetical operation is " + "of wrong data type")); + } else if (arg0->type == node_type_number) { + switch (node->v.bin.opcode) { + case bin_add: + if (arg0->v.number == 0) { + copy_node(node, arg1); + free_node(arg0); + free(arg1); + } + break; + + case bin_sub: + if (arg0->v.number == 0) { + NODE *n = alloc_node(node_type_un, + &node->locus); + n->v.un.opcode = unary_minus; + n->v.un.arg = arg1; + copy_node(node, n); + free_node(arg0); + free(n); + } + break; + + case bin_mul: + if (arg0->v.number == 0) { + node->type = node_type_number; + node->v.number = 0; + free_node(arg0); + free_node(arg1); + } else if (arg0->v.number == 1) { + copy_node(node, arg1); + free_node(arg0); + } + break; + + case bin_div: + if (arg0->v.number == 0) { + node->type = node_type_number; + node->v.number = 0; + free_node(arg0); + free_node(arg1); + } + break; + + case bin_logand: + if (arg0->v.number == 0) { + node->type = node_type_number; + node->v.number = 0; + free_node(arg0); + free_node(arg1); + } else if (arg0->v.number == ~(unsigned long)0) { + copy_node(node, arg1); + free_node(arg0); + } + break; + + case bin_logor: + if (arg0->v.number == 0) { + copy_node(node, arg1); + free_node(arg0); + } else if (arg0->v.number == ~(unsigned long)0) { + node->type = node_type_number; + node->v.number = ~(unsigned long)0; + free_node(arg0); + free_node(arg1); + } + break; + + case bin_logxor: + if (arg0->v.number == 0) { + copy_node(node, arg1); + free_node(arg0); + } + break; + + default: + return; + } + } else if (arg1->type == node_type_number) { + switch (node->v.bin.opcode) { + case bin_add: + case bin_sub: + if (arg1->v.number == 0) { + copy_node(node, arg0); + free_node(arg1); + free(arg0); + } + break; + + case bin_mul: + if (arg1->v.number == 0) { + node->type = node_type_number; + node->v.number = 0; + free_node(arg0); + free_node(arg1); + } else if (arg1->v.number == 1) { + copy_node(node, arg0); + free_node(arg1); + } + break; + + case bin_div: + if (arg1->v.number == 0) { + parse_error_locus(&node->locus, + _("division by zero")); + } else if (arg1->v.number == 1) { + copy_node(node, arg0); + free_node(arg1); + } + break; + + case bin_logand: + if (arg1->v.number == 0) { + node->type = node_type_number; + node->v.number = 0; + free_node(arg0); + free_node(arg1); + } else if (arg1->v.number == ~(unsigned long)0) { + copy_node(node, arg0); + free_node(arg1); + } + break; + + case bin_logor: + if (arg1->v.number == 0) { + copy_node(node, arg0); + free_node(arg1); + } else if (arg1->v.number == ~(unsigned long)0) { + node->type = node_type_number; + node->v.number = ~(unsigned long)0; + free_node(arg0); + free_node(arg1); + } + break; + + case bin_logxor: + if (arg1->v.number == 0) { + copy_node(node, arg0); + free_node(arg0); + } + break; + + default: + return; + } + } +} + +void +optimize_relational(NODE *node) +{ + NODE *arg0 = node->v.bin.arg[0]; + NODE *arg1 = node->v.bin.arg[1]; + if (arg0->type == node_type_number + && arg1->type == node_type_number) { + switch (node->v.bin.opcode) { + case bin_and: + node->v.number = arg0->v.number && arg1->v.number; + break; + + case bin_or: + node->v.number = arg0->v.number || arg1->v.number; + break; + + case bin_eq: + node->v.number = arg0->v.number == arg1->v.number; + break; + + case bin_ne: + node->v.number = arg0->v.number != arg1->v.number; + break; + + case bin_lt: + node->v.number = arg0->v.number < arg1->v.number; + break; + + case bin_le: + node->v.number = arg0->v.number <= arg1->v.number; + break; + + case bin_gt: + node->v.number = arg0->v.number > arg1->v.number; + break; + + case bin_ge: + node->v.number = arg0->v.number >= arg1->v.number; + break; + + default: + return; + } + } else if (arg0->type == node_type_string + && arg1->type == node_type_string) { + switch (node->v.bin.opcode) { + case bin_and: + node->v.number = arg0->v.literal->text[0] != 0 + && arg1->v.literal->text[0] != 0; + break; + + case bin_or: + node->v.number = arg0->v.literal->text[0] != 0 + || arg1->v.literal->text[0] != 0; + break; + + case bin_eq: + /* NOTE: This case and the one below make use of the + fact that no two entries in the symbol table can + contain lexicographically equal literals */ + node->v.number = arg0->v.literal == arg1->v.literal; + break; + + case bin_ne: + node->v.number = arg0->v.literal != arg1->v.literal; + break; + + case bin_lt: + node->v.number = strcmp(arg0->v.literal->text, + arg1->v.literal->text) < 0; + break; + + case bin_le: + node->v.number = strcmp(arg0->v.literal->text, + arg1->v.literal->text) <= 0; + break; + + case bin_gt: + node->v.number = strcmp(arg0->v.literal->text, + arg1->v.literal->text) > 0; + break; + + case bin_ge: + node->v.number = strcmp(arg0->v.literal->text, + arg1->v.literal->text) >= 0; + break; + + default: + return; + } + } else + return; + node->type = node_type_number; + free_node(arg0); + free_node(arg1); +} + +static int +node_regmatch(NODE *node, struct literal *lit) +{ + regex_t re; + struct sym_regex *sym = node->v.regex; + int rc; + + rc = regcomp(&re, sym->lit->text, sym->regflags); + if (rc) { + char errbuf[512]; + regerror(rc, &re, errbuf, sizeof(errbuf)); + parse_error_locus(&node->locus, + _("Cannot compile regex: %s"), + errbuf); + return 1; + } + rc = regexec(&re, lit->text, 0, NULL, 0); + regfree(&re); + return rc; +} + +void +optimize_type_bin(NODE *node) +{ + NODE *arg0, *arg1; + + arg0 = node->v.bin.arg[0]; + arg1 = node->v.bin.arg[1]; + optimize(arg0); + optimize(arg1); + + switch (node->v.bin.opcode) { + case bin_and: + case bin_or: + case bin_eq: + case bin_ne: + case bin_lt: + case bin_le: + case bin_gt: + case bin_ge: + optimize_relational(node); + break; + + case bin_add: + case bin_sub: + case bin_mul: + case bin_div: + case bin_logand: + case bin_logor: + case bin_logxor: + optimize_arith(node); + break; + + case bin_match: + if (node_type(arg0) != dtype_string) { + parse_error_locus(&arg0->locus, + _("left-hand side argument " + "to match is " + "of wrong data type")); + } else if (arg1->type == node_type_regex) { + if (arg0->type == node_type_string) { + node->v.number = + node_regmatch(arg1, + arg0->v.literal) == 0; + node->type = node_type_number; + free_node(arg0); + free_node(arg1); + } + } else if (arg1->type != node_type_regcomp) { + parse_error_locus(&arg1->locus, + _("right-hand side argument " + "to match is " + "of wrong data type " + "(should not happen)")); + } + break; + + case bin_fnmatch: + if (arg0->type == node_type_string + && arg1->type == node_type_string) { + node->v.number = fnmatch(arg1->v.literal->text, + arg0->v.literal->text, + 0) == 0; + node->type = node_type_number; + free_node(arg0); + free_node(arg1); + } else if (node_type(arg0) != dtype_string) { + parse_error_locus(&arg0->locus, + _("left-hand side argument " + "to fnmatch is of wrong data type")); + } else if (node_type(arg1) != dtype_string) { + parse_error_locus(&arg1->locus, + _("right-hand side argument " + "to fnmatch is of wrong data type")); + } + break; + } +} + +#define __code_cat3__(a,b,c) a ## b ## c + +#define CODE_BINARY(op, node) do { \ + switch (node_type(node->v.bin.arg[0])) { \ + case dtype_number: \ + code_op(__code_cat3__(opcode_,op,n)); \ + break; \ + case dtype_string: \ + code_op(__code_cat3__(opcode_,op,s)); \ + break; \ + default: \ + parse_error_locus(&node->locus, \ + _("Invalid argument type in binary operation")); \ + break; \ + } \ +} while (0) + +void +code_type_bin(NODE *node, struct locus **old_locus) +{ + prog_counter_t pos1, pos2; + + code_node(node->v.bin.arg[0]); + + switch (node->v.bin.opcode) { + case bin_and: + MARK_LOCUS(); + /* cond1 + if not true goto X + cond2 + if true goto Y + X: push 0 + goto Z + Y: push 1 + Z: */ + code_op(opcode_bz); + pos1 = code_immediate(NULL); + code_node(node->v.bin.arg[1]); + code_op(opcode_bnz); + pos2 = code_immediate((void *)4); + code_op(opcode_push); + code_immediate((void *)0); + code_op(opcode_jmp); + code_immediate((void *)2); + code_op(opcode_push); + code_immediate((void*)1); + code_put(pos1, (void *)(pos2 - pos1)); + break; + + case bin_or: + MARK_LOCUS(); + /* cond1 + if true goto X + cond2 + if not true goto Y + X: push 1 + goto Z + Y: push 0 + Z: */ + + code_op(opcode_bnz); + pos1 = code_immediate(NULL); + code_node(node->v.bin.arg[1]); + code_op(opcode_bz); + pos2 = code_immediate((void *)4); + code_op(opcode_push); + code_immediate((void *)1); + code_op(opcode_jmp); + code_immediate((void *)2); + code_op(opcode_push); + code_immediate((void *)0); + code_put(pos1, (void *)(pos2 - pos1)); + break; + + case bin_eq: + code_node(node->v.bin.arg[1]); + CODE_BINARY(eq, node); + break; + + case bin_ne: + code_node(node->v.bin.arg[1]); + CODE_BINARY(ne, node); + break; + + case bin_lt: + code_node(node->v.bin.arg[1]); + CODE_BINARY(lt, node); + break; + + case bin_le: + code_node(node->v.bin.arg[1]); + CODE_BINARY(le, node); + break; + + case bin_gt: + code_node(node->v.bin.arg[1]); + CODE_BINARY(gt, node); + break; + + case bin_ge: + code_node(node->v.bin.arg[1]); + CODE_BINARY(ge, node); + break; + + case bin_match: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + if (node->v.bin.qualifier & QUALIFIER_MX) + code_op(opcode_regmatch_mx); + else + code_op(opcode_regmatch); + break; + + case bin_fnmatch: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + if (node->v.bin.qualifier & QUALIFIER_MX) + code_op(opcode_fnmatch_mx); + else + code_op(opcode_fnmatch); + break; + + case bin_add: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_add); + break; + + case bin_sub: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_sub); + break; + + case bin_mul: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_mul); + break; + + case bin_div: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_div); + break; + + case bin_logand: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_logand); + break; + + case bin_logor: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_logor); + break; + + case bin_logxor: + code_node(node->v.bin.arg[1]); + MARK_LOCUS(); + code_op(opcode_logxor); + break; + + default: + break; + } +} + + +/* type un */ + +void +print_type_un(NODE *node, int level) +{ + print_level(level); + switch (node->v.un.opcode) { + case unary_not: + printf("NOT\n"); + break; + case unary_minus: + printf("NEG\n"); + break; + default: + abort(); + } + print_node(node->v.un.arg, level+1); +} + +void +mark_type_un(NODE *node) +{ + mark(node->v.un.arg); +} + +void +optimize_type_un(NODE *node) +{ + NODE *p = node->v.un.arg; + optimize(p); + if (p->type == node_type_number) { + switch (node->v.un.opcode) { + case unary_not: + node->v.number = !p->v.number; + break; + + case unary_minus: + node->v.number = -p->v.number; + break; + + case unary_lognot: + node->v.number = ~p->v.number; + break; + } + node->type = node_type_number; + free_node(p); + } +} + +void +code_type_un(NODE *node, struct locus **old_locus) +{ + code_node(node->v.un.arg); + MARK_LOCUS(); + switch (node->v.un.opcode) { + case unary_not: + code_op(opcode_not); + break; + + case unary_minus: + code_op(opcode_neg); + break; + + case unary_lognot: + code_op(opcode_lognot); + break; + + default: + abort(); + } +} + + +/* type result */ + +void +print_type_result(NODE *node, int level) +{ + if (node->v.ret.code) { + const char *s = NULL; + int expr = 0; + + print_level(level); + if (node->v.ret.message) { + if (node->v.ret.message->type == node_type_string) + s = node->v.ret.message->v.literal->text; + else { + expr = 1; + s = "(expression)"; + } + } + dbg_setreply(NULL, + (char*) LITERAL_TEXT(node->v.ret.code), + (char*) LITERAL_TEXT(node->v.ret.xcode), + (char*) s); + if (expr) + print_node(node->v.ret.message, level+1); + } + print_level(level); + print_stat(node->v.ret.stat); + printf("\n"); +} + +void +mark_type_result(NODE *node) +{ + if (node->v.ret.code) + node->v.ret.code->flags |= VAR_REFERENCED; + if (node->v.ret.xcode) + node->v.ret.xcode->flags |= VAR_REFERENCED; + mark(node->v.ret.message); +} + +void +optimize_type_result(NODE *node) +{ + optimize(node->v.ret.message); +} + +void +code_type_result(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + if (node->v.ret.message) + code_node(node->v.ret.message); + else { + code_op(opcode_push); + code_immediate(NULL); + } + MARK_LOCUS(); + code_op(opcode_result); + code_immediate((void*)node->v.ret.stat); + code_immediate((void*)LITERAL_OFF(node->v.ret.code)); + code_immediate((void*)LITERAL_OFF(node->v.ret.xcode)); + code_op(opcode_nil); +} + + +/* type header */ + +void +print_type_header(NODE *node, int level) +{ + print_level(level); + printf("%s %s: \n", msgmod_opcode_str(node->v.hdr.opcode), + node->v.hdr.name->text); + print_node_list(node->v.hdr.value, level+1); +} + +void +mark_type_header(NODE *node) +{ + node->v.hdr.name->flags |= VAR_REFERENCED; + mark(node->v.hdr.value); +} + +void +optimize_type_header(NODE *node) +{ + optimize(node->v.hdr.value); +} + +void +code_type_header(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + if (node->v.hdr.value) + code_node(node->v.hdr.value); + else { + code_op(opcode_push); + code_immediate(0); + } + code_op(opcode_header); + code_immediate((void*)node->v.hdr.opcode); + code_immediate((void*)node->v.hdr.name->off); +} + + +/* type builtin */ + +void +print_type_builtin(NODE *node, int level) +{ + print_level(level); + printf("BUILTIN %s\n", node->v.builtin.builtin->name); + print_node_list_reverse(node->v.builtin.args, level+1); +} + +void +mark_type_builtin(NODE *node) +{ + unsigned i; + NODE *p; + struct literal *s = literal_lookup(node->v.builtin.builtin->name); + + s->flags |= VAR_REFERENCED; + for (i = 0, p = node->v.builtin.args; p; i++, p = p->next) + mark(p); +} + +void +optimize_type_builtin(NODE *node) +{ + size_t i; + NODE *p; + + for (i = 0, p = node->v.builtin.args; p; i++, p = p->next) + optimize(p); + if (strcmp(node->v.builtin.builtin->name, "interval") == 0) { + if (node->v.builtin.args->type == node_type_string) { + time_t t; + const char *endp; + + if (parse_time_interval( + node->v.builtin.args->v.literal->text, + &t, &endp)) { + parse_error_locus(&node->locus, + _("Unrecognized time format (near `%s')"), + endp); + return; + } + /* Replace this node */ + node->type = node_type_number; + node->v.number = t; + } + } +} + +void +code_type_builtin(NODE *node, struct locus **old_locus) +{ + NODE *p; + int i; + const struct builtin *bp = node->v.builtin.builtin; + struct literal *s; + + /* Pass arguments */ + for (p = node->v.builtin.args, i = 0; p; p = p->next, i++) + code_node(p); + if (bp->optcount || bp->varargs) { + /* Pass the number of actual arguments in a hidden arg */ + code_op(opcode_push); + code_immediate((void*)i); + } + + MARK_LOCUS(); + code_op(opcode_builtin); + s = literal_lookup(node->v.builtin.builtin->name); + code_immediate((void*)s->off); + code_immediate((void*)node->v.builtin.builtin->handler); +} + + +/* type concat */ + +void +print_type_concat(NODE *node, int level) +{ + print_level(level); + printf("CONCAT:\n"); + print_node(node->v.concat.arg[0], level+1); + print_node(node->v.concat.arg[1], level+1); +} + +void +mark_type_concat(NODE *node) +{ + mark(node->v.concat.arg[0]); + mark(node->v.concat.arg[1]); +} + +void +optimize_type_concat(NODE *node) +{ + NODE *arg0, *arg1; + + optimize(node->v.concat.arg[0]); + optimize(node->v.concat.arg[1]); + arg0 = node->v.concat.arg[0]; + arg1 = node->v.concat.arg[1]; + if (arg0->type == node_type_string + && arg1->type == node_type_string) { + string_begin(); + string_add(arg0->v.literal->text, + strlen(arg0->v.literal->text)); + string_add(arg1->v.literal->text, + strlen(arg1->v.literal->text)); + node->v.literal = string_finish(); + node->type = node_type_string; + free_node(arg0); + free_node(arg1); + } else if (arg0->type == node_type_string + && arg0->v.literal->text[0] == 0) { + copy_node(node, arg1); + free_node(arg0); + } else if (arg1->type == node_type_string + && arg1->v.literal->text[0] == 0) { + copy_node(node, arg0); + free_node(arg1); + } +} + +void +code_type_concat(NODE *node, struct locus **old_locus) +{ + code_node(node->v.concat.arg[0]); + code_node(node->v.concat.arg[1]); + code_op(opcode_concat); +} + + +/* type variable */ + +void +print_type_variable(NODE *node, int level) +{ + print_level(level); + printf("VARIABLE %s %s %lu(%lu)\n", + storage_class_str(node->v.var_ref.variable->storage_class), + node->v.var_ref.variable->name, + (unsigned long) node->v.var_ref.nframes, + (unsigned long) node->v.var_ref.variable->off); +} + +void +mark_type_variable(NODE *node) +{ + if (node->v.var_ref.variable->storage_class == storage_extern) + node->v.var_ref.variable->flags |= VAR_REFERENCED; +} + +void +code_type_variable(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + code_memref(node); + code_op(opcode_deref); +} + + +/* type asgn */ + +void +print_type_asgn(NODE *node, int level) +{ + print_level(level); + printf("SET %s %s %lu(%lu)\n", + storage_class_str(node->v.asgn.var->storage_class), + node->v.asgn.var->name, + (unsigned long) node->v.asgn.nframes, + (unsigned long) node->v.asgn.var->off); + print_node(node->v.asgn.node, level + 1); +} + +void +mark_type_asgn(NODE *node) +{ + mark(node->v.asgn.node); +} + +void +optimize_type_asgn(NODE *node) +{ + optimize(node->v.asgn.node); +} + +void +code_type_asgn(NODE *node, struct locus **old_locus) +{ + code_node(node->v.asgn.node); + node->v.asgn.var->type = node_type(node->v.asgn.node); + code_memref(node); + code_op(opcode_asgn); +} + + +/* type arg */ + +void +print_type_arg(NODE *node, int level) +{ + print_level(level); + printf("ARG %u\n", node->v.arg.number); +} + +void +code_type_arg(NODE *node, struct locus **old_locus) +{ + MARK_LOCUS(); + code_op(opcode_memstk); + code_immediate((void*)0); + code_immediate((void*)(node->v.arg.number + 2)); + code_op(opcode_deref); +} + + + +char * +regex_flags_to_string(int flags, char *buf, size_t size) +{ + static struct { + unsigned flag; + char *name; + } regflg[] = { + { REG_EXTENDED, REG_EXTENDED_NAME }, + { REG_ICASE, REG_ICASE_NAME }, + { REG_NEWLINE, REG_NEWLINE_NAME } + }; + char *p; + int i; + + p = buf; + size--; + for (i = 0; i < NELEMS(regflg) && size > 0; i++) { + if (regflg[i].flag & flags) { + size_t len = strlen(regflg[i].name); + if (p > buf) + len++; + if (len > size) + len = size; + if (p > buf) { + *p++ = ','; + len--; + } + if (len > 0) { + memcpy(p, regflg[i].name, len); + p += len; + } + size -= len; + } + } + *p = 0; + return buf; +} + +/* type regex */ +void +print_type_regex(NODE *node, int level) +{ + char buffer[REGEX_STRING_BUFSIZE]; + print_ |