Hi Andrei,
does the switch support only integers?
Apart of return code from functions, most of the switches I have seen are for strings (e.g., matching dialed number/address, user IDs, etc...).
Cheers, Daniel
On 02/04/2009 09:50 PM, Andrei Pelinescu-Onciul wrote:
Module: sip-router Branch: andrei/switch Commit: a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a29a8b6d...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Wed Feb 4 20:44:26 2009 +0100
script parsing: C style switch() & case support
- support for parsing C style switch() & case, e.g.: switch($var){ case 1: log(1, "1\n"); break; case 2: case 3: default: log(1, "default\n"); } (note: this is different from kamailio/openser switch())
cfg.lex | 7 +++ cfg.y | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- route_struct.h | 8 +++- switch.h | 60 +++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-)
diff --git a/cfg.lex b/cfg.lex index fc9eecb..13767b1 100644 --- a/cfg.lex +++ b/cfg.lex @@ -187,6 +187,9 @@ ELSE "else" SET_ADV_ADDRESS "set_advertised_address" SET_ADV_PORT "set_advertised_port" FORCE_SEND_SOCKET "force_send_socket" +SWITCH "switch" +CASE "case" +DEFAULT "default"
/*ACTION LVALUES*/ URIHOST "uri:host" @@ -495,6 +498,10 @@ EAT_ABLE [\ \t\b\r] return SET_ADV_PORT; } <INITIAL>{FORCE_SEND_SOCKET} { count(); yylval.strval=yytext; return FORCE_SEND_SOCKET; } +<INITIAL>{SWITCH} { count(); yylval.strval=yytext; return SWITCH; } +<INITIAL>{CASE} { count(); yylval.strval=yytext; return CASE; } +<INITIAL>{DEFAULT} { count(); yylval.strval=yytext; return DEFAULT; }
<INITIAL>{URIHOST} { count(); yylval.strval=yytext; return URIHOST; } <INITIAL>{URIPORT} { count(); yylval.strval=yytext; return URIPORT; } diff --git a/cfg.y b/cfg.y index 63c9eb4..431054d 100644 --- a/cfg.y +++ b/cfg.y @@ -93,6 +93,7 @@
lval=rval_expr, where lval=avp|pvar (andrei)
- 2007-12-06 expression are now evaluated in terms of rvalues;
NUMBER is now always positive; cleanup (andrei)
- 2009-01-26 case/switch() support (andrei)
*/
%{ @@ -109,6 +110,7 @@ #include "route_struct.h" #include "globals.h" #include "route.h" +#include "switch.h" #include "dprint.h" #include "sr_module.h" #include "modparam.h" @@ -211,6 +213,8 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int); static void free_name_lst(struct name_lst* lst); static void free_socket_id_lst(struct socket_id* i);
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a);
%}
%union { @@ -219,6 +223,7 @@ static void free_socket_id_lst(struct socket_id* i); char* strval; struct expr* expr; struct action* action;
- struct case_stms* case_stms; struct net* ipnet; struct ip_addr* ipaddr; struct socket_id* sockid;
@@ -272,6 +277,9 @@ static void free_socket_id_lst(struct socket_id* i); %token SET_ADV_ADDRESS %token SET_ADV_PORT %token FORCE_SEND_SOCKET +%token SWITCH +%token CASE +%token DEFAULT %token URIHOST %token URIPORT %token MAX_LEN @@ -493,6 +501,8 @@ static void free_socket_id_lst(struct socket_id* i); %type <intval> intno eint_op eint_op_onsend %type <intval> eip_op eip_op_onsend %type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action +%type <action> switch_cmd +%type <case_stms> single_case case_stms %type <ipaddr> ipv4 ipv6 ipv6addr ip %type <ipnet> ipnet %type <strval> host @@ -514,7 +524,7 @@ static void free_socket_id_lst(struct socket_id* i); %type <attr> attr_id_any_str %type <pvar> pvar %type <lval> lval -%type <rv_expr> rval rval_expr +%type <rv_expr> rval rval_expr ct_rval %type <lval> avp_pvar /* %type <intval> class_id */ %type <intval> assign_op @@ -1762,6 +1772,7 @@ actions: action: fcmd SEMICOLON {$$=$1;} | if_cmd {$$=$1;}
- | switch_cmd {$$=$1;} | assign_action SEMICOLON {$$=$1;} | SEMICOLON /* null action */ {$$=0;} | fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
@@ -1770,6 +1781,98 @@ if_cmd: IF exp stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); } | IF exp stm ELSE stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); } ;
+ct_rval: rval_expr {
$$=0;
if (!rve_is_constant($1)){
yyerror("constant expected");
}else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
yyerror("invalid expression (bad type)");
}else if (i_tmp!=RV_INT){
yyerror("invalid expression type, int expected\n");
}else
$$=$1;
}
+; +single_case:
- CASE ct_rval COLON actions {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, $4))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | CASE ct_rval COLON {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, 0))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | DEFAULT COLON actions {
if (($$=mk_case_stm(0, $3))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | DEFAULT COLON {
if (($$=mk_case_stm(0, 0))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | CASE error { $$=0; yyerror("bad case label"); }
- | CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); }
+; +case_stms:
- case_stms single_case {
$$=$1;
if ($2==0) yyerror ("bad case");
if ($$){
*($$->append)=$2;
if (*($$->append)!=0)
$$->append=&((*($$->append))->next);
}
- }
- | single_case {
$$=$1;
if ($1==0) yyerror ("bad case");
else $$->append=&($$->next);
- }
+; +switch_cmd:
SWITCH rval_expr LBRACE case_stms RBRACE {
$$=0;
if ($2==0) yyerror("bad expression in switch(...)");
else if ($4==0) yyerror ("bad switch body");
else{
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH rval_expr LBRACE RBRACE {
$$=0;
warn("empty switch()");
if ($2==0) yyerror("bad expression in switch(...)");
else{
/* it might have sideffects, so leave it for the optimizer */
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); }
- | SWITCH rval_expr LBRACE error RBRACE
{$$=0; yyerror ("bad switch body"); }
+;
/* class_id: LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; } | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; } @@ -2763,6 +2866,23 @@ static void free_socket_id_lst(struct socket_id* lst) } }
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) +{
- struct case_stms* s;
- s=pkg_malloc(sizeof(*s));
- if (s==0) {
LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
- } else {
memset(s, 0, sizeof(*s));
s->ct_rve=ct;
s->actions=a;
s->next=0;
s->append=0;
- }
- return s;
+}
/* int main(int argc, char ** argv) { diff --git a/route_struct.h b/route_struct.h index 76aac25..e87b2d0 100644 --- a/route_struct.h +++ b/route_struct.h @@ -70,7 +70,9 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O, enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
IF_T, SWITCH_T /* only until fixup*/,
BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
SETFLAG_T, RESETFLAG_T, ISFLAGSET_T , AVPFLAG_OPER_T, LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T,MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
@@ -96,7 +98,9 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST, MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST, SELECT_ST, PVAR_ST, LVAL_ST, RVE_ST,
RETCODE_ST};
RETCODE_ST, CASE_ST,
BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
+};
/* run flags */ #define EXIT_R_F 1 diff --git a/switch.h b/switch.h new file mode 100644 index 0000000..4c9f78b --- /dev/null +++ b/switch.h @@ -0,0 +1,60 @@ +/*
- $Id$
- Copyright (C) 2009 iptelorg GmbH
- Permission to use, copy, modify, and distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
+/*
- /home/andrei/sr.git/switch.h
- */
+/*
- History:
- 2009-02-02 initial version (andrei)
+*/
+#ifndef __switch_h +#define __switch_h
+#include "route_struct.h"
+struct case_stms{
- struct rval_expr* ct_rve;
- struct action* actions;
- struct case_stms* next;
- struct case_stms** append;
- int int_label;
- int is_default;
+};
+struct switch_cond_table{
- int n; /**< size */
- int* cond; /**< int labels array */
- struct action** jump; /**< jump points array */
- struct action* def; /**< default jump */
+};
+struct switch_jmp_table{
- int first; /**< first int label in the jump table */
- int last; /**< last int label in the jump table */
- struct action** tbl; /**< jmp table [v-first] iff first<=v<=last */
- struct switch_cond_table rest; /**< normal cond. table for the rest */
+};
+#endif /*__switch_h*/
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
sr-dev mailing list sr-dev@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev