]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch.y
LUA: port luadb to dbapi2 to drop postgres dependency
[irc/quakenet/newserv.git] / newsearch / newsearch.y
1 %{
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdarg.h>
5 #include "../lib/stringbuf.h"
6 #include "newsearch.h"
7 #include "parser.h"
8
9 #define YYSTYPE sstring *
10
11 int yylex(void);
12 extern char *parseStrError;
13 extern int parseStrErrorPos;
14
15 #define MAXSTACKSIZE 50
16
17 typedef struct parserlist {
18 searchASTExpr expr;
19 struct parserlist *next;
20 } parserlist;
21
22 static int stackpos;
23 static parserlist *stack[MAXSTACKSIZE];
24 static int stackcount[MAXSTACKSIZE];
25 static fnFinder functionfinder;
26 static void *fnfarg;
27 static parsertree **presult, sresult;
28
29 extern int lexerror, lexpos;
30 void yystrerror(const char *format, ...);
31 void lexreset(void);
32
33 void resetparser(fnFinder fnf, void *arg, parsertree **result) {
34 presult = result;
35 *presult = &sresult;
36
37 sresult.exprlist = NULL;
38 sresult.strlist = NULL;
39 sresult.finished = 0;
40
41 functionfinder = fnf;
42 fnfarg = arg;
43
44 stackpos = 0;
45 lexreset();
46 }
47
48 void yyerror(const char *str) {
49 if(lexerror) {
50 lexerror = 0;
51 yystrerror("lexical error");
52 return;
53 }
54
55 parseStrError = (char *)str;
56 parseStrErrorPos = lexpos;
57 }
58
59 void yystrerror(const char *format, ...) {
60 va_list va;
61 static char buf[512];
62
63 parse_free(&sresult);
64
65 va_start(va, format);
66 vsnprintf(buf, sizeof(buf), format, va);
67 va_end(va);
68
69 yyerror(buf);
70 }
71
72 %}
73
74 %token LPAREN RPAREN WHITESPACE IDENTIFIER STRING
75
76 %%
77 invocation: LPAREN function argumentlist RPAREN
78 {
79 sstring *str = $2;
80 int i, count;
81 searchASTExpr *ap, *root;
82 parserlist *pp, *npp;
83 expressionlist *xl;
84 parseFunc pfn;
85
86 stackpos--;
87 count = stackcount[stackpos];
88
89 pfn = functionfinder(str->content, fnfarg);
90 if(!pfn) {
91 yystrerror("unknown function: %s", str->content);
92 YYERROR;
93 }
94 /* if we're at the top of the stack we're the root of the tree */
95 if(stackpos != 0) {
96 /*
97 * we store this function containing its children in the stack list
98 * as there might be functions or other stuff after it, such as:
99 * (fn (fn2) moo moo)
100 */
101 parserlist *rootp = malloc(sizeof(searchASTExpr) + sizeof(parserlist));
102 root = &rootp->expr;
103
104 stackcount[stackpos-1]++;
105 rootp->next = stack[stackpos-1];
106 stack[stackpos-1] = rootp;
107 } else {
108 /* need space for the final result and real root */
109 *presult = malloc(sizeof(parsertree) + sizeof(searchASTExpr));
110
111 memcpy(*presult, &sresult, sizeof(parsertree));
112 (*presult)->finished = 1;
113
114 root = (*presult)->root;
115 }
116
117 xl = malloc(sizeof(expressionlist) + sizeof(searchASTExpr) * count);
118 xl->next = (*presult)->exprlist;
119 (*presult)->exprlist = xl;
120
121 ap = xl->expr;
122 for(i=count-1,pp=stack[stackpos];i>=0;i--,pp=npp) {
123 npp = pp->next;
124 memcpy(&ap[i], &pp->expr, sizeof(searchASTExpr));
125 free(pp);
126 }
127 *root = NSASTManualNode(pfn, count, ap);
128
129 freesstring(str);
130 }
131
132 function: IDENTIFIER
133 {
134 if(stackpos >= MAXSTACKSIZE - 1) {
135 yyerror("function stack overflow");
136 YYERROR;
137 }
138
139 stackcount[stackpos] = 0;
140 stack[stackpos] = NULL;
141
142 stackpos++;
143 };
144
145 argumentlist: /* empty */ | WHITESPACE argument argumentlist;
146
147 argument:
148 invocation | literal
149 {
150 sstring *str = $1;
151 parserlist *l = malloc(sizeof(parserlist));
152
153 if(str) {
154 stringlist *sl;
155 l->expr = NSASTLiteral(str->content);
156
157 sl = malloc(sizeof(stringlist));
158 sl->data = str;
159 sl->next = (*presult)->strlist;
160 (*presult)->strlist = sl;
161 } else {
162 l->expr = NSASTLiteral("");
163 }
164
165 l->next = stack[stackpos - 1];
166 stack[stackpos - 1] = l;
167 stackcount[stackpos - 1]++;
168
169 }
170 ;
171
172 literal: IDENTIFIER | STRING;