aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-10-03 15:47:06 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-10-03 15:47:06 +0300
commit1026a8cc51d8c72a2237ce06467fd84fe3c303f9 (patch)
tree4b8b122a8387ae048fc5a778f4eb3c940b579a2b
parentec9b2d3c5dd6c6ea9d3569c358746d00c053d03a (diff)
downloadmailfromd-1026a8cc51d8c72a2237ce06467fd84fe3c303f9.tar.gz
mailfromd-1026a8cc51d8c72a2237ce06467fd84fe3c303f9.tar.bz2
Implement explicit concatenation operator (.)
* mfd/drivers.c (type strcat): A synonym for concat, used for implicit string concatenation. * mfd/gram.y: Expect 53 shift/reduces. (alloc_node, cast_to): extern (T_COMPOSE): New token. (concat_expr): New %type. (concat_expr): New rule. (node_type): handle node_type_strcat. (create_node_variable, create_node_argcount) (create_node_arg, create_node_symbol) (create_node_backref): New functions. * mfd/lex.l: Rewrite string handling. Strings with variable and/or constant substitutions within them are handled in one run and a corresponding NODE* is composed out of them. That node is then returned as T_COMPOSE token. * mfd/prog.h (alloc_node, cast_to) (create_node_variable, create_node_argcount) (create_node_arg, create_node_symbol) (create_node_backref): New protos. * mflib/sa.mf, mflib/spf.mf, tests/alias.at, tests/curmsg.at, tests/etc/ack.rc, tests/etc/catch.rc, tests/etc/catch01.rc, tests/etc/public.mf, tests/hdr-all.at, tests/hdr-cap.at, tests/hdr-count.at, tests/hdr-get.at, tests/hdr-gete.at, tests/hdr-getn.at, tests/hdr-itr.at, tests/hdr-mul.at, tests/macros.at, tests/next01.at, tests/next02.at, tests/prec.at, tests/public.at, tests/shadow.at, tests/static01.at: Use explicit concatenation. * tests/prec01.at: New testcase. * tests/Makefile.am, tests/testsuite.at: Add prec01.at
-rw-r--r--mfd/drivers.c26
-rw-r--r--mfd/gram.y144
-rw-r--r--mfd/lex.l255
-rw-r--r--mfd/prog.h8
-rw-r--r--mflib/sa.mf10
-rw-r--r--mflib/spf.mf12
-rw-r--r--mflib/strip_domain_part.mf2
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/alias.at4
-rw-r--r--tests/curmsg.at2
-rw-r--r--tests/etc/ack.rc2
-rw-r--r--tests/etc/catch.rc2
-rw-r--r--tests/etc/catch01.rc2
-rw-r--r--tests/etc/public.mf2
-rw-r--r--tests/hdr-all.at2
-rw-r--r--tests/hdr-cap.at6
-rw-r--r--tests/hdr-count.at2
-rw-r--r--tests/hdr-get.at4
-rw-r--r--tests/hdr-gete.at2
-rw-r--r--tests/hdr-getn.at6
-rw-r--r--tests/hdr-itr.at2
-rw-r--r--tests/hdr-mul.at6
-rw-r--r--tests/macros.at2
-rw-r--r--tests/next01.at2
-rw-r--r--tests/next02.at2
-rw-r--r--tests/prec.at10
-rw-r--r--tests/public.at4
-rw-r--r--tests/shadow.at2
-rw-r--r--tests/static01.at4
-rw-r--r--tests/testsuite.at1
30 files changed, 384 insertions, 145 deletions
diff --git a/mfd/drivers.c b/mfd/drivers.c
index 5dc594b1..fbd8a88c 100644
--- a/mfd/drivers.c
+++ b/mfd/drivers.c
@@ -1165,6 +1165,32 @@ code_type_concat(NODE *node, struct locus **old_locus)
code_node(node->v.concat.arg[1]);
code_op(opcode_concat);
}
+
+/* type strcat */
+
+void
+print_type_strcat(NODE *node, int level)
+{
+ print_type_concat(node, level);
+}
+
+void
+mark_type_strcat(NODE *node)
+{
+ mark_type_concat(node);
+}
+
+void
+optimize_type_strcat(NODE *node)
+{
+ optimize_type_concat(node);
+}
+
+void
+code_type_strcat(NODE *node, struct locus **old_locus)
+{
+ code_type_concat(node, old_locus);
+}
/* type variable */
diff --git a/mfd/gram.y b/mfd/gram.y
index 7c25fba1..32d79f57 100644
--- a/mfd/gram.y
+++ b/mfd/gram.y
@@ -27,7 +27,6 @@
#include "prog.h"
#include "optab.h"
-static NODE *alloc_node(enum node_type type, const struct locus *locus);
static void free_node(NODE *node);
static void set_poll_arg(struct poll_data *poll, int kw, NODE *expr);
static int codegen(prog_counter_t *pc, NODE *node, unsigned exmask,
@@ -43,7 +42,6 @@ static NODE *function_call(struct function *function, size_t count,
static NODE *declare_function(struct function *func, struct locus *loc,
size_t nautos);
static data_type_t node_type(NODE *node);
-static NODE *cast_to(data_type_t type, NODE *node);
static NODE *cast_arg_list(NODE *args, size_t parmc, data_type_t *parmtype,
int disable_prom);
static void add_xref(struct variable *var, const struct locus *locus);
@@ -288,7 +286,7 @@ _create_alias(void *item, void *data)
%}
%error-verbose
-%expect 28
+%expect 53
%union {
struct literal *literal;
@@ -409,6 +407,7 @@ _create_alias(void *item, void *data)
T_PUBLIC "public"
T_MODULE "module"
T_BYE "bye"
+%token <node> T_COMPOSE "composed string"
%token T_MODBEG T_MODEND
%token <literal> T_STRING "string"
%token <literal> T_SYMBOL "MTA macro" T_IDENTIFIER "identifier"
@@ -420,7 +419,7 @@ _create_alias(void *item, void *data)
%token <string> T_SHARPREQR
%token T_BOGUS
-%left T_CONCAT
+%left '.'
%left T_OR
%left T_AND
%left T_NOT
@@ -437,7 +436,7 @@ _create_alias(void *item, void *data)
%type <node> decl stmt condition action sendmail_action header_action
if_cond else_cond on_cond atom argref paren_argref
funcall proccall expr maybe_expr maybe_xcode_expr
- common_expr simp_expr atom_expr
+ common_expr concat_expr simp_expr atom_expr
asgn catch throw return case_cond autodcl constdecl
loopstmt opt_while jumpstmt
%type <stmtlist> program stmtlist decllist modcntl
@@ -1676,11 +1675,29 @@ maybe_expr : /* empty */
| expr
;
-common_expr: simp_expr
- | common_expr simp_expr %prec T_CONCAT
+common_expr: concat_expr
+ | common_expr '.' concat_expr
{
$$ = alloc_node(node_type_concat, get_locus());
$$->v.concat.arg[0] = cast_to(dtype_string, $1);
+ $$->v.concat.arg[1] = cast_to(dtype_string, $3);
+ }
+ ;
+
+concat_expr: simp_expr
+ | concat_expr simp_expr
+ {
+ if (($1->type == node_type_string
+ || $1->type == node_type_strcat)
+ && ($2->type == node_type_string
+ || $2->type == node_type_strcat))
+ $$ = alloc_node(node_type_strcat, get_locus());
+ else {
+ deprecation_warning(_("implicit concatenation is deprecated"));
+ deprecation_warning(_("use `.' operator"));
+ $$ = alloc_node(node_type_concat, get_locus());
+ }
+ $$->v.concat.arg[0] = cast_to(dtype_string, $1);
$$->v.concat.arg[1] = cast_to(dtype_string, $2);
}
;
@@ -1692,7 +1709,15 @@ simp_expr : atom_expr
$$->v.bin.opcode = bin_add;
$$->v.bin.arg[0] = cast_to(dtype_number, $1);
$$->v.bin.arg[1] = cast_to(dtype_number, $3);
- }
+ }
+/*
+ | simp_expr '.' simp_expr
+ {
+ $$ = alloc_node(node_type_concat, get_locus());
+ $$->v.concat.arg[0] = cast_to(dtype_string, $1);
+ $$->v.concat.arg[1] = cast_to(dtype_string, $3);
+ }
+*/
| simp_expr '-' simp_expr
{
$$ = alloc_node(node_type_bin, get_locus());
@@ -1763,9 +1788,7 @@ atom_expr : funcall
atom : T_SYMBOL
{
- register_macro(state_tag, $1->text);
- $$ = alloc_node(node_type_symbol, get_locus());
- $$->v.literal = $1;
+ $$ = create_node_symbol($1, get_locus());
}
| value
{
@@ -1786,25 +1809,12 @@ atom : T_SYMBOL
}
| T_BACKREF
{
- $$ = alloc_node(node_type_backref, get_locus());
- $$->v.number = $1;
+ $$ = create_node_backref($1, get_locus());
}
| argref
| T_ARGCOUNT
{
- if (outer_context == context_function) {
- if (func->optcount || func->varargs) {
- $$ = alloc_node(node_type_arg, &$1);
- $$->v.arg.data_type = dtype_number;
- $$->v.arg.number = 1;
- } else {
- $$ = alloc_node(node_type_number, &$1);
- $$->v.number = parminfo[outer_context].parmcount();
- }
- } else {
- $$ = alloc_node(node_type_number, &$1);
- $$->v.number = parminfo[outer_context].parmcount();
- }
+ $$ = create_node_argcount(&$1);
}
| '@' T_IDENTIFIER
{
@@ -1823,26 +1833,16 @@ atom : T_SYMBOL
$$ = alloc_node(node_type_vaptr, get_locus());
$$->v.node = $2;
}
+ | T_COMPOSE
;
argref : variable
{
- $$ = alloc_node(node_type_variable, get_locus());
- $$->v.var_ref.variable = $1;
- $$->v.var_ref.nframes = catch_nesting;
+ $$ = create_node_variable($1, get_locus());
}
| T_ARG
{
- if (inner_context == context_function
- && func->varargs)
- ;
- else if ($1 > PARMCOUNT())
- parse_error(_("argument number too high"));
- $$ = alloc_node(node_type_arg, get_locus());
- $$->v.arg.data_type = PARMTYPE($1);
- $$->v.arg.number = $1;
- if (inner_context == context_function)
- $$->v.arg.number += FUNC_HIDDEN_ARGS(func);
+ $$ = create_node_arg($1, get_locus());
}
| T_ARGX '(' expr ')'
{
@@ -3838,6 +3838,7 @@ node_type(NODE *node)
return node->v.builtin.builtin->rettype;
case node_type_concat:
+ case node_type_strcat:
return dtype_string;
case node_type_variable:
@@ -4521,3 +4522,68 @@ declare_function(struct function *func, struct locus *loc, size_t nautos)
return node;
}
+
+NODE *
+create_node_variable(struct variable *var, const struct locus *locus)
+{
+ NODE *node = alloc_node(node_type_variable, locus);
+ node->v.var_ref.variable = var;
+ node->v.var_ref.nframes = catch_nesting;
+ return node;
+}
+
+NODE *
+create_node_argcount(const struct locus *locus)
+{
+ NODE *node;
+
+ if (outer_context == context_function) {
+ if (func->optcount || func->varargs) {
+ node = alloc_node(node_type_arg, locus);
+ node->v.arg.data_type = dtype_number;
+ node->v.arg.number = 1;
+ } else {
+ node = alloc_node(node_type_number, locus);
+ node->v.number = parminfo[outer_context].parmcount();
+ }
+ } else {
+ node = alloc_node(node_type_number, locus);
+ node->v.number = parminfo[outer_context].parmcount();
+ }
+ return node;
+}
+
+NODE *
+create_node_arg(long num, const struct locus *locus)
+{
+ NODE *node;
+
+ if (inner_context == context_function && func->varargs)
+ ;
+ else if (num > PARMCOUNT())
+ parse_error(_("argument number too high"));
+ node = alloc_node(node_type_arg, locus);
+ node->v.arg.data_type = PARMTYPE(num);
+ node->v.arg.number = num;
+ if (inner_context == context_function)
+ node->v.arg.number += FUNC_HIDDEN_ARGS(func);
+ return node;
+}
+
+NODE *
+create_node_symbol(struct literal *lit, const struct locus *locus)
+{
+ NODE *node;
+ register_macro(state_tag, lit->text);
+ node = alloc_node(node_type_symbol, locus);
+ node->v.literal = lit;
+ return node;
+}
+
+NODE *
+create_node_backref(long num, const struct locus *locus)
+{
+ NODE *node = alloc_node(node_type_backref, locus);
+ node->v.number = num;
+ return node;
+}
diff --git a/mfd/lex.l b/mfd/lex.l
index 30ebb935..96802bbe 100644
--- a/mfd/lex.l
+++ b/mfd/lex.l
@@ -297,6 +297,114 @@ advance_line()
/* Redeclare main entry point. Actual yylex is defined in the code section
below. */
#define YY_DECL static int lexscan(void)
+
+
+/* String composer */
+static NODE *string_head, *string_tail;
+
+static void
+compose_add_node(NODE *node)
+{
+ if (string_tail)
+ string_tail->next = node;
+ else
+ string_head = node;
+ string_tail = node;
+}
+
+static void
+compose_start(int state)
+{
+ if (string_head) {
+ parse_error("INTERNAL ERROR: previous composition has not "
+ "finished when a new one started");
+ abort();
+ }
+ BEGIN_X(state);
+}
+
+static int
+compose_finish()
+{
+ if (string_tail != string_head) {
+ while (string_head->next) {
+ NODE *cat = alloc_node(node_type_strcat,
+ &string_head->locus);
+ NODE *next = string_head->next;
+ cat->next = next->next;
+ cat->v.concat.arg[0] = cast_to(dtype_string,
+ string_head);
+ cat->v.concat.arg[1] = cast_to(dtype_string, next);
+ string_head->next = next->next = NULL;
+ string_head = cat;
+ }
+ }
+ yylval.node = string_head;
+ string_head = string_tail = NULL;
+ return T_COMPOSE;
+}
+
+static void
+compose_add_literal(struct literal *lit)
+{
+ NODE *node = alloc_node(node_type_string, &locus);
+ node->v.literal = lit;
+ compose_add_node(node);
+ if (yy_flex_debug)
+ fprintf(stderr, "--add literal: '%s'\n", lit->text);
+}
+
+static void
+compose_add_string(const char *text, size_t length)
+{
+ compose_add_literal(string_alloc(text, length));
+}
+
+static void
+compose_add_number(long num)
+{
+ NODE *node = alloc_node(node_type_number, &locus);
+ node->v.number = num;
+ compose_add_node(node);
+}
+
+void
+compose_add_builtin_const(const char *s, size_t len)
+{
+ const char *sval;
+ long nval;
+
+ switch (builtin_const_value(s, len, &sval, &nval)) {
+ case dtype_number:
+ compose_add_number(nval);
+ break;
+
+ case dtype_string:
+ compose_add_string(sval, strlen(sval));
+ break;
+
+ default:
+ abort();
+ }
+}
+
+void
+compose_add_variable_or_const(int what)
+{
+ switch (what) {
+ case T_NUMBER:
+ compose_add_number(yylval.number);
+ break;
+
+ case T_STRING:
+ compose_add_literal(yylval.literal);
+ break;
+
+ case T_VARIABLE:
+ compose_add_node(create_node_variable(yylval.var, &locus));
+ }
+}
+
%}
/* Exclusive states:
@@ -453,31 +561,50 @@ bye return keyword(T_BYE);
<ONBLOCK>host return keyword(T_HOST);
<ONBLOCK>as return keyword(T_AS);
/* Variables */
-<INITIAL,ONBLOCK,ML,CML,STR>\%({ICONST}) {
+<INITIAL,ONBLOCK>\%({ICONST}) {
return builtin_const(yytext + 1, yyleng - 1);
}
-<INITIAL,ONBLOCK,ML,CML,STR>\%\{({ICONST})\} {
+<ML,CML,STR>\%({ICONST}) {
+ compose_add_builtin_const(yytext + 1, yyleng - 1);
+}
+<INITIAL,ONBLOCK>\%\{({ICONST})\} {
return builtin_const(yytext + 2, yyleng - 3);
}
-<INITIAL,ONBLOCK,ML,CML,STR>\%{IDENT} {
+<ML,CML,STR>\%\{({ICONST})\} {
+ compose_add_builtin_const(yytext + 2, yyleng - 3);
+}
+<INITIAL,ONBLOCK>\%{IDENT} {
string(yytext + 1, yyleng - 1);
return variable_or_const();
}
-<INITIAL,ONBLOCK,ML,CML,STR>\%\{{IDENT}\} {
+<ML,CML,STR>\%{IDENT} {
+ string(yytext + 1, yyleng - 1);
+ compose_add_variable_or_const(variable_or_const());
+}
+<INITIAL,ONBLOCK>\%\{{IDENT}\} {
string(yytext + 2, yyleng - 3);
return variable_or_const();
}
-
+<ML,CML,STR>\%\{{IDENT}\} {
+ string(yytext + 2, yyleng - 3);
+ compose_add_variable_or_const(variable_or_const());
+}
/* Positional arguments */
-<INITIAL,ONBLOCK,ML,CML,STR>\$# {
+<INITIAL,ONBLOCK>\$# {
return T_ARGCOUNT;
}
-<INITIAL,ONBLOCK,ML,CML,STR>\${P} {
+<ML,CML,STR>\$# {
+ compose_add_node(create_node_argcount(&locus));
+}
+<INITIAL,ONBLOCK>\${P} {
yylval.number = strtol(yytext + 1, NULL, 0);
return T_ARG; }
+<ML,CML,STR>\${P} {
+ compose_add_node(create_node_arg(strtol(yytext + 1, NULL, 0), &locus));
+ }
<INITIAL,ONBLOCK>\$/"(" { return keyword(T_ARGX); }
/* Sendmail variables */
-<INITIAL,ONBLOCK,ML,CML,STR>\${IDENT} {
+<INITIAL,ONBLOCK>\${IDENT} {
if (yyleng == 2)
string(yytext + 1, 1);
else {
@@ -489,17 +616,35 @@ bye return keyword(T_BYE);
}
return T_SYMBOL;
}
-<INITIAL,ONBLOCK,ML,CML,STR>\$\{{IDENT}\} {
+<ML,CML,STR>\${IDENT} {
+ if (yyleng == 2)
+ string(yytext + 1, 1);
+ else {
+ line_begin();
+ line_add("{", 1);
+ line_add(yytext + 1, yyleng - 1);
+ line_add("}", 1);
+ line_finish();
+ }
+ compose_add_node(create_node_symbol(yylval.literal, &locus));
+ }
+<INITIAL,ONBLOCK>\$\{{IDENT}\} {
string(yytext+1, yyleng - 1); return T_SYMBOL; }
+<ML,CML,STR>\$\{{IDENT}\} {
+ string(yytext+1, yyleng - 1);
+ compose_add_node(create_node_symbol(yylval.literal, &locus)); }
/* Back-references */
-<INITIAL,ONBLOCK,ML,CML,STR>\\{P} {
+<INITIAL,ONBLOCK>\\{P} {
yylval.number = strtoul(yytext+1, NULL, 0);
return T_BACKREF; }
+<ML,CML,STR>\\{P} {
+ compose_add_node(create_node_backref(strtoul(yytext+1, NULL, 10),
+ &locus)); }
/* Numeric strings */
0[xX]{X}{X}* { yylval.number = strtoul(yytext, NULL, 16); return T_NUMBER; };
0{O}{O}* { yylval.number = strtoul(yytext, NULL, 8); return T_NUMBER; };
0|{P} { yylval.number = strtoul(yytext, NULL, 10); return T_NUMBER; };
- /* Strings */
+ /* Identifiers */
{IDENT} {
int paren_follows = 0;
enum { is_ident, is_builtin, is_func } state;
@@ -535,83 +680,74 @@ bye return keyword(T_BYE);
return T_IDENTIFIER;
}
}
+ /* Strings */
'[^\n']*' { string(yytext+1, yyleng-2); return T_STRING; }
\"[^\\\"$%\n]*\" { string(yytext+1, yyleng-2); return T_STRING; }
\"[^\\\"$%\n]*\\\n { advance_line();
- BEGIN_X(STR);
- line_begin();
- line_add(yytext + 1, yyleng - 3); }
-\"[^\\\"$%\n]*/[\\$%] { BEGIN_X(STR);
- string(yytext+1, yyleng-1);
- line_begin();
- return T_STRING; }
+ compose_start(STR);
+ compose_add_string(yytext + 1, yyleng - 3); }
+\"[^\\\"$%\n]*/[\\$%] { compose_start(STR);
+ compose_add_string(yytext+1, yyleng-1); }
\"\\x{X}{X}/[\\$%] {
- BEGIN_X(STR);
+ compose_start(STR);
line_add_char(strtoul(yytext + 3, NULL, 16));
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
}
\"\\x{X}{X} {
- BEGIN_X(STR);
+ compose_start(STR);
line_add_char(strtoul(yytext + 3, NULL, 16));
}
\"\\0{O}{1,3}/[\\$%] {
- BEGIN_X(STR);
+ compose_start(STR);
line_add_char(strtoul(yytext + 3, NULL, 8));
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
}
\"\\0{O}{1,3} {
- BEGIN_X(STR);
+ compose_start(STR);
line_add_char(strtoul(yytext + 3, NULL, 8));
}
\"\\[^1-9]/[\\$%] {
- BEGIN_X(STR);
+ compose_start(STR);
line_add_char(mu_argcv_unquote_char(yytext[2]));
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
}
\"\\[^1-9] {
- BEGIN_X(STR);
+ compose_start(STR);
line_add_char(mu_argcv_unquote_char(yytext[2]));
}
<STR>[^\\\"$%\n]*\\\n { advance_line(); line_add(yytext, yyleng - 2); }
<STR>[^\\\"$%\n]*\" { BEGIN(INITIAL);
- if (yyleng > 1)
- line_add(yytext, yyleng - 1);
- line_finish();
- return T_STRING; }
+ if (yyleng > 1)
+ line_add(yytext, yyleng - 1);
+ compose_add_literal(string_finish());
+ return compose_finish(); }
<STR>[^\\\"$%\n]+/[\\$%] {
line_add(yytext, yyleng);
- line_finish();
+ compose_add_literal(string_finish());
line_begin();
- return T_STRING;
}
<STR,ML,CML>\\x{X}{X}/[\\$%] {
line_add_char(strtoul(yytext + 2, NULL, 16));
- line_finish();
+ compose_add_literal(string_finish());
line_begin();
- return T_STRING;
}
<STR,ML,CML>\\x{X}{X} {
line_add_char(strtoul(yytext + 2, NULL, 16));
}
<STR,ML,CML>\\0{O}{1,3}/[\\$%] {
line_add_char(strtoul(yytext + 2, NULL, 8));
- line_finish();
+ compose_add_literal(string_finish());
line_begin();
- return T_STRING;
}
<STR,ML,CML>\\0{O}{1,3} {
line_add_char(strtoul(yytext + 2, NULL, 8));
}
<STR,ML,CML>\\[^1-9]/[\\$%] {
line_add_char(mu_argcv_unquote_char(yytext[1]));
- line_finish();
+ compose_add_literal(string_finish());
line_begin();
- return T_STRING;
}
<STR,ML,CML>\\[^1-9] {
line_add_char(mu_argcv_unquote_char(yytext[1]));
@@ -655,9 +791,9 @@ bye return keyword(T_BYE);
memcpy(multiline_delimiter, p, multiline_delimiter_len);
multiline_delimiter[multiline_delimiter_len] = 0;
if (multiline_unescape)
- BEGIN_X(ML);
+ compose_start(ML);
else
- BEGIN_X(QML);
+ compose_start(QML);
}
/* Quoted multilines */
<QML>[^\\\n]*\n {
@@ -676,8 +812,8 @@ bye return keyword(T_BYE);
multiline_delimiter = NULL;
multiline_delimiter_len = 0;
BEGIN(INITIAL);
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
+ return compose_finish();
}
line_add(p, strlen(p));
}
@@ -689,20 +825,18 @@ bye return keyword(T_BYE);
for (; char_to_strip (*p); p++)
;
line_add(p, strlen(p));
- line_finish();
- BEGIN(CML);
- return T_STRING;
+ compose_add_literal(string_finish());
+ BEGIN_X(CML);
}
<CML>[^\\$%\n]+/[\\$%] {
line_add(yytext, yyleng);
- line_finish();
+ compose_add_literal(string_finish());
line_begin();
- return T_STRING;
}
<CML,STR>"%%"|"$$" {
line_add(yytext, 1);
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
+ line_begin();
}
<ML,CML,STR>[$%] {
line_add(yytext, yyleng);
@@ -723,12 +857,11 @@ bye return keyword(T_BYE);
multiline_delimiter = NULL;
multiline_delimiter_len = 0;
BEGIN(INITIAL);
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
+ return compose_finish();
}
line_add(p, strlen(p));
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
}
<ML>[^\\$%\n]*\n {
char *p;
@@ -746,8 +879,8 @@ bye return keyword(T_BYE);
multiline_delimiter = NULL;
multiline_delimiter_len = 0;
BEGIN(INITIAL);
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
+ return compose_finish();
}
line_add(p, strlen(p));
}
@@ -761,8 +894,8 @@ bye return keyword(T_BYE);
multiline_delimiter = NULL;
multiline_delimiter_len = 0;
BEGIN(INITIAL);
- line_finish();
- return T_STRING;
+ compose_add_literal(string_finish());
+ return compose_finish();
}
line_add(yytext, yyleng);
BEGIN_X(ML);
diff --git a/mfd/prog.h b/mfd/prog.h
index 21e5c6f2..995b26bb 100644
--- a/mfd/prog.h
+++ b/mfd/prog.h
@@ -72,6 +72,14 @@ void enter_loop(struct literal *lit,
prog_counter_t *begptr, prog_counter_t *endptr);
void leave_loop(void);
+NODE *alloc_node(enum node_type type, const struct locus *locus);
+NODE *create_node_variable(struct variable *var, const struct locus *locus);
+NODE *create_node_argcount(const struct locus *locus);
+NODE *create_node_arg(long num, const struct locus *locus);
+NODE *create_node_symbol(struct literal *lit, const struct locus *loc);
+NODE *create_node_backref(long num, const struct locus *locus);
+NODE *cast_to(data_type_t type, NODE *node);
+
extern instr_t *prog;
extern unsigned error_count;
extern unsigned long prog_trace_option;
diff --git a/mflib/sa.mf b/mflib/sa.mf
index 89fb850f..7e5266b5 100644
--- a/mflib/sa.mf
+++ b/mflib/sa.mf
@@ -23,10 +23,10 @@ static func __sa_format_score0(string code, number prec)
do
number len length(%code)
if %len > %prec
- return substring(%code, 0, %len - %prec-1) '.'
+ return substring(%code, 0, %len - %prec-1) . '.' .
substring(%code, %len - %prec, -1)
else
- return "0." replstr("0", %prec - %len) %code
+ return "0." . replstr("0", %prec - %len) . %code
fi
done
@@ -40,7 +40,7 @@ func sa_format_score(number code, number prec)
returns string
do
if %code < 0
- return "-" __sa_format_score0(- %code, %prec)
+ return "-" . __sa_format_score0(- %code, %prec)
else
return __sa_format_score0(%code, %prec)
fi
@@ -80,10 +80,10 @@ do
fi
number n index(%text, "\n", %i)
if %n >= 0
- set ret %ret %pfx substring(%text, %i, %n)
+ set ret %ret . %pfx . substring(%text, %i, %n)
set i %n + 1
else
- set ret %ret %pfx substr(%text, %i)
+ set ret %ret . %pfx . substr(%text, %i)
break
fi
done
diff --git a/mflib/spf.mf b/mflib/spf.mf
index be6343bf..889d09da 100644
--- a/mflib/spf.mf
+++ b/mflib/spf.mf
@@ -42,7 +42,7 @@ do
case TempError: return "TempError"
case PermError: return "PermError"
done
- return "UNKNOWN (" %code ")"
+ return "UNKNOWN (%code)"
done
static func __spf_get_cache(string ip, string domain, string sender)
@@ -76,22 +76,22 @@ static func __spf_put_cache(number result, string ip, string domain,
string sender)
do
safedbput(%spf_database, "%ip-%domain-%sender",
- (time() + %spf_ttl)
+ (time() + %spf_ttl) .
" %result <%spf_mechanism> <%spf_explanation>")
done
static func __spf_log(number result, string ip, string domain, string sender)
do
- string logmsg "SPF check_host(%ip, %domain, %sender) = "
+ string logmsg "SPF check_host(%ip, %domain, %sender) = " .
spf_status_string(%result)
if %spf_cached
- set logmsg %logmsg " [CACHED]"
+ set logmsg "%logmsg [CACHED]"
fi
if %spf_mechanism != ""
- set logmsg %logmsg "; matching mechanism \"%spf_mechanism\""
+ set logmsg "%logmsg; matching mechanism \"%spf_mechanism\""
fi
if %spf_explanation != ""
- set logmsg %logmsg "; %spf_explanation"
+ set logmsg "%logmsg; %spf_explanation"
fi
echo "$i: %logmsg"
done
diff --git a/mflib/strip_domain_part.mf b/mflib/strip_domain_part.mf
index 1de92fe1..4be44dc5 100644
--- a/mflib/strip_domain_part.mf
+++ b/mflib/strip_domain_part.mf
@@ -22,7 +22,7 @@ func strip_domain_part(string domain, number n)
do
if %n = 0
return domainpart %domain
- elif domainpart(%domain) matches '.*((\.[^.]+){' %n '})'
+ elif domainpart(%domain) matches '.*((\.[^.]+){' . %n . '})'
return substring(\1, 1, -1)
else
return %domain
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e6d3b960..19a0d720 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -101,6 +101,7 @@ TESTSUITE_AT = \
poll04.at\
public.at\
prec.at\
+ prec01.at\
rcptargs