Module: sip-router
Branch: andrei/switch
Commit: a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a29a8b6…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)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: */