[SR-Dev] git:andrei/switch: script parsing: C style switch() & case support
Daniel-Constantin Mierla
miconda at gmail.com
Wed Feb 4 22:18:40 CET 2009
On 02/04/2009 10:58 PM, Andrei Pelinescu-Onciul wrote:
> 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.
>
There are couple of advantages:
1) config clarity - instead of a long
if (a==... || a==...)
you have
switch(a) {
case ...:
case ...:
}
2) it can shorten the script and save some ifs:
switch(a) {
case v1:
something;
case v2:
something else;
break;
}
This is equivalent of:
if(a==v1) {
something;
}
if(a==v1 || a==v2){
something;
something else;
}
or
if(a==v1) {
something;
something else;
}
if(a==v2){
something else;
}
3) although not implemented yet in kamailio/openser (but planned),
inside 'break' can make code cleaner
switch(a) {
case v1:
...
if(...) {
break;
}
...
break;
}
4) traditionally, as I could learn, pstn switching/old telco school guys
feel more confortable with line oriented routing rules, where they had
something like:
extension match "1234": call emergency;
It could be a sswitch (although I would prefer single name to avoid
confusions) if breaks logic for integer optimizations.
Cheers,
Daniel
> 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
>>
--
Daniel-Constantin Mierla
http://www.asipto.com
More information about the sr-dev
mailing list