[SR-Dev] git:andrei/switch: script parsing: C style switch() & case support
Daniel-Constantin Mierla
miconda at gmail.com
Wed Feb 4 21:29:03 CET 2009
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=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