[SR-Dev] git:andrei/switch: script parsing: C style switch() & case support

Andrei Pelinescu-Onciul andrei at iptel.org
Wed Feb 4 21:58:21 CET 2009


On Feb 04, 2009 at 22:29, Daniel-Constantin Mierla <miconda at gmail.com> wrote:
> 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...).

Yes, it's only for integers.

For strings, ifs should be used, since the switch wouldn't bring any
advantage.

Andrei


> 
> 
> 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=a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5
> >
> >Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
> >Committer: Andrei Pelinescu-Onciul <andrei at 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,
> >+		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, 
> >MODULEX_T,
> > 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
> > 		AVPFLAG_OPER_T,
> > 		LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_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 at lists.sip-router.org
> >http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
> >  
> 
> -- 
> Daniel-Constantin Mierla
> http://www.asipto.com



More information about the sr-dev mailing list