Browse code

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())

Andrei Pelinescu-Onciul authored on 04/02/2009 19:44:26
Showing 4 changed files
... ...
@@ -187,6 +187,9 @@ ELSE			"else"
187 187
 SET_ADV_ADDRESS	"set_advertised_address"
188 188
 SET_ADV_PORT	"set_advertised_port"
189 189
 FORCE_SEND_SOCKET	"force_send_socket"
190
+SWITCH			"switch"
191
+CASE			"case"
192
+DEFAULT			"default"
190 193
 
191 194
 /*ACTION LVALUES*/
192 195
 URIHOST			"uri:host"
... ...
@@ -495,6 +498,10 @@ EAT_ABLE	[\ \t\b\r]
495 495
 										return SET_ADV_PORT; }
496 496
 <INITIAL>{FORCE_SEND_SOCKET}	{	count(); yylval.strval=yytext;
497 497
 									return FORCE_SEND_SOCKET; }
498
+<INITIAL>{SWITCH}	{ count(); yylval.strval=yytext; return SWITCH; }
499
+<INITIAL>{CASE}	{ count(); yylval.strval=yytext; return CASE; }
500
+<INITIAL>{DEFAULT}	{ count(); yylval.strval=yytext; return DEFAULT; }
501
+
498 502
 
499 503
 <INITIAL>{URIHOST}	{ count(); yylval.strval=yytext; return URIHOST; }
500 504
 <INITIAL>{URIPORT}	{ count(); yylval.strval=yytext; return URIPORT; }
... ...
@@ -93,6 +93,7 @@
93 93
  *               lval=rval_expr, where lval=avp|pvar  (andrei)
94 94
  * 2007-12-06  expression are now evaluated in terms of rvalues;
95 95
  *             NUMBER is now always positive; cleanup (andrei)
96
+ * 2009-01-26  case/switch() support (andrei)
96 97
 */
97 98
 
98 99
 %{
... ...
@@ -109,6 +110,7 @@
109 109
 #include "route_struct.h"
110 110
 #include "globals.h"
111 111
 #include "route.h"
112
+#include "switch.h"
112 113
 #include "dprint.h"
113 114
 #include "sr_module.h"
114 115
 #include "modparam.h"
... ...
@@ -211,6 +213,8 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int);
211 211
 static void free_name_lst(struct name_lst* lst);
212 212
 static void free_socket_id_lst(struct socket_id* i);
213 213
 
214
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a);
215
+
214 216
 %}
215 217
 
216 218
 %union {
... ...
@@ -219,6 +223,7 @@ static void free_socket_id_lst(struct socket_id* i);
219 219
 	char* strval;
220 220
 	struct expr* expr;
221 221
 	struct action* action;
222
+	struct case_stms* case_stms;
222 223
 	struct net* ipnet;
223 224
 	struct ip_addr* ipaddr;
224 225
 	struct socket_id* sockid;
... ...
@@ -272,6 +277,9 @@ static void free_socket_id_lst(struct socket_id* i);
272 272
 %token SET_ADV_ADDRESS
273 273
 %token SET_ADV_PORT
274 274
 %token FORCE_SEND_SOCKET
275
+%token SWITCH
276
+%token CASE
277
+%token DEFAULT
275 278
 %token URIHOST
276 279
 %token URIPORT
277 280
 %token MAX_LEN
... ...
@@ -493,6 +501,8 @@ static void free_socket_id_lst(struct socket_id* i);
493 493
 %type <intval> intno eint_op eint_op_onsend
494 494
 %type <intval> eip_op eip_op_onsend
495 495
 %type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action
496
+%type <action> switch_cmd
497
+%type <case_stms> single_case case_stms
496 498
 %type <ipaddr> ipv4 ipv6 ipv6addr ip
497 499
 %type <ipnet> ipnet
498 500
 %type <strval> host
... ...
@@ -514,7 +524,7 @@ static void free_socket_id_lst(struct socket_id* i);
514 514
 %type <attr> attr_id_any_str
515 515
 %type <pvar> pvar
516 516
 %type <lval> lval
517
-%type <rv_expr> rval rval_expr 
517
+%type <rv_expr> rval rval_expr ct_rval
518 518
 %type <lval> avp_pvar
519 519
 /* %type <intval> class_id */
520 520
 %type <intval> assign_op
... ...
@@ -1762,6 +1772,7 @@ actions:
1762 1762
 action:
1763 1763
 	fcmd SEMICOLON {$$=$1;}
1764 1764
 	| if_cmd {$$=$1;}
1765
+	| switch_cmd {$$=$1;}
1765 1766
 	| assign_action SEMICOLON {$$=$1;}
1766 1767
 	| SEMICOLON /* null action */ {$$=0;}
1767 1768
 	| fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
... ...
@@ -1770,6 +1781,98 @@ if_cmd:
1770 1770
 	IF exp stm		{ $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); }
1771 1771
 	| IF exp stm ELSE stm	{ $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); }
1772 1772
 	;
1773
+
1774
+ct_rval: rval_expr {
1775
+			$$=0;
1776
+			if (!rve_is_constant($1)){
1777
+				yyerror("constant expected");
1778
+			}else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
1779
+				yyerror("invalid expression (bad type)");
1780
+			}else if (i_tmp!=RV_INT){
1781
+				yyerror("invalid expression type, int expected\n");
1782
+			}else
1783
+				$$=$1;
1784
+		}
1785
+;
1786
+single_case:
1787
+	CASE ct_rval COLON actions {
1788
+		$$=0;
1789
+		if ($2==0) yyerror ("bad case label");
1790
+		else if (($$=mk_case_stm($2, $4))==0){
1791
+				yyerror("internal error: memory allocation failure");
1792
+				YYABORT;
1793
+		}
1794
+	}
1795
+	| CASE ct_rval COLON {
1796
+		$$=0;
1797
+		if ($2==0) yyerror ("bad case label");
1798
+		else if (($$=mk_case_stm($2, 0))==0){
1799
+				yyerror("internal error: memory allocation failure");
1800
+				YYABORT;
1801
+		}
1802
+	}
1803
+	| DEFAULT COLON actions {
1804
+		if (($$=mk_case_stm(0, $3))==0){
1805
+				yyerror("internal error: memory allocation failure");
1806
+				YYABORT;
1807
+		}
1808
+	}
1809
+	| DEFAULT COLON {
1810
+		if (($$=mk_case_stm(0, 0))==0){
1811
+				yyerror("internal error: memory allocation failure");
1812
+				YYABORT;
1813
+		}
1814
+	}
1815
+	| CASE error { $$=0; yyerror("bad case label"); }
1816
+	| CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); }
1817
+;
1818
+case_stms:
1819
+	case_stms single_case {
1820
+		$$=$1;
1821
+		if ($2==0) yyerror ("bad case");
1822
+		if ($$){
1823
+			*($$->append)=$2;
1824
+			if (*($$->append)!=0)
1825
+				$$->append=&((*($$->append))->next);
1826
+		}
1827
+	}
1828
+	| single_case {
1829
+		$$=$1;
1830
+		if ($1==0) yyerror ("bad case");
1831
+		else $$->append=&($$->next);
1832
+	}
1833
+;
1834
+switch_cmd:
1835
+	  SWITCH rval_expr LBRACE case_stms RBRACE { 
1836
+		$$=0;
1837
+		if ($2==0) yyerror("bad expression in switch(...)");
1838
+		else if ($4==0) yyerror ("bad switch body");
1839
+		else{
1840
+			$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
1841
+			if ($$==0) {
1842
+				yyerror("internal error");
1843
+				YYABORT;
1844
+			}
1845
+		}
1846
+	}
1847
+	| SWITCH rval_expr LBRACE RBRACE {
1848
+		$$=0;
1849
+		warn("empty switch()");
1850
+		if ($2==0) yyerror("bad expression in switch(...)");
1851
+		else{
1852
+			/* it might have sideffects, so leave it for the optimizer */
1853
+			$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0);
1854
+			if ($$==0) {
1855
+				yyerror("internal error");
1856
+				YYABORT;
1857
+			}
1858
+		}
1859
+	}
1860
+	| SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); }
1861
+	| SWITCH rval_expr LBRACE error RBRACE 
1862
+		{$$=0; yyerror ("bad switch body"); }
1863
+;
1864
+
1773 1865
 /* class_id:
1774 1866
 	LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; }
1775 1867
 	| LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; }
... ...
@@ -2763,6 +2866,23 @@ static void free_socket_id_lst(struct socket_id* lst)
2763 2763
 	}
2764 2764
 }
2765 2765
 
2766
+
2767
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a)
2768
+{
2769
+	struct case_stms* s;
2770
+	s=pkg_malloc(sizeof(*s));
2771
+	if (s==0) {
2772
+		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2773
+	} else {
2774
+		memset(s, 0, sizeof(*s));
2775
+		s->ct_rve=ct;
2776
+		s->actions=a;
2777
+		s->next=0;
2778
+		s->append=0;
2779
+	}
2780
+	return s;
2781
+}
2782
+
2766 2783
 /*
2767 2784
 int main(int argc, char ** argv)
2768 2785
 {
... ...
@@ -70,7 +70,9 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
70 70
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
71 71
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
72 72
 		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
73
-		IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
73
+		IF_T, SWITCH_T /* only until fixup*/,
74
+		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
75
+		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
74 76
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
75 77
 		AVPFLAG_OPER_T,
76 78
 		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,
96 96
 		MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST,
97 97
 		SELECT_ST, PVAR_ST,
98 98
 		LVAL_ST,  RVE_ST,
99
-		RETCODE_ST};
99
+		RETCODE_ST, CASE_ST,
100
+		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
101
+};
100 102
 
101 103
 /* run flags */
102 104
 #define EXIT_R_F   1
103 105
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2009 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * /home/andrei/sr.git/switch.h
19
+ */
20
+/*
21
+ * History:
22
+ * --------
23
+ *  2009-02-02  initial version (andrei)
24
+*/
25
+
26
+#ifndef __switch_h
27
+#define __switch_h
28
+
29
+#include "route_struct.h"
30
+
31
+struct case_stms{
32
+	struct rval_expr* ct_rve;
33
+	struct action* actions;
34
+	struct case_stms* next;
35
+	struct case_stms** append;
36
+	int int_label;
37
+	int is_default;
38
+};
39
+
40
+
41
+struct switch_cond_table{
42
+	int n;                  /**< size */
43
+	int* cond;              /**< int labels array */
44
+	struct action** jump;   /**< jump points array */
45
+	struct action* def; /**< default jump  */
46
+};
47
+
48
+
49
+struct switch_jmp_table{
50
+	int first;              /**< first int label in the jump table */
51
+	int last;               /**< last int label in the jump table */
52
+	struct action** tbl;    /**< jmp table [v-first] iff first<=v<=last */
53
+	struct switch_cond_table rest; /**< normal cond. table for the rest */
54
+};
55
+
56
+
57
+#endif /*__switch_h*/
58
+
59
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */