]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Add new newsearch parser.
authorChris Porter <redacted>
Sun, 21 Sep 2008 00:38:09 +0000 (01:38 +0100)
committerChris Porter <redacted>
Sun, 21 Sep 2008 00:38:09 +0000 (01:38 +0100)
Currently disabled by default.

.hgignore
build.mk.in
newsearch/Makefile.in
newsearch/newsearch.c
newsearch/newsearch.l [new file with mode: 0644]
newsearch/newsearch.y [new file with mode: 0644]
newsearch/parser.c [new file with mode: 0644]
newsearch/parser.h [new file with mode: 0644]

index 42f1d25e2711f0987ea14bca926ea5529c3579d9..8d385447b6821ffff2f5e4c086d6b2baaae32ebd 100644 (file)
--- a/.hgignore
+++ b/.hgignore
@@ -30,3 +30,5 @@ graphing/dump
 silly
 core/hooks.c
 lib/sstring.{c,h}
+y.tab.{c,h}
+lex.yy.c
index 4d711c6ab37d525bc0a02bf056448848126fdaed..827e105b0656d36aef6d4047d09ae13afb319c83 100644 (file)
@@ -11,10 +11,14 @@ CC=gcc
 BUILDID @shell@ (hg id || echo "unknown") | sed -e "s/+ /-/;s/ /-/" @shellend@
 @endif@
 
-.SUFFIXES: .so
+.SUFFIXES: .so .y .l
 
 .o.so:
        @-ldline-@ $(LDFLAGS)
 
+.y.c:  ;
+
+.l.c:  ;
+
 CFLAGS+=-Wall -g -finline-functions -funroll-loops -std=c99 -I./ -DBUILDID=$(BUILDID)
 CFLAGS+=-fPIC -export-dynamic
index 1db8321f4dd9f4841a58b487136b3b3acbd8922d..8ef3b3e9c28773dece194196510285e6e98d0688 100644 (file)
@@ -1,9 +1,18 @@
 @include@ @includel@../build.mk@includel@
 
-CFLAGS+=$(INCPCRE)
+CFLAGS+=$(INCPCRE) -DYY_NO_UNPUT
 LDFLAGS+=$(LIBPCRE)
 
 .PHONY: all
 all: newsearch.so
 
-newsearch.so: newsearch.o formats.o ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o ns-authid.o ns-notice.o newsearch_ast.o ns-any.o ns-channeliter.o ns-var.o ns-all.o ns-cumodes.o ns-cidr.o
+newsearch.so: newsearch.o formats.o y.tab.o lex.yy.o parser.o ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o ns-authid.o ns-notice.o newsearch_ast.o ns-any.o ns-channeliter.o ns-var.o ns-all.o ns-cumodes.o ns-cidr.o
+
+y.tab.c y.tab.h: newsearch.y
+       ${YACC} -d newsearch.y
+
+lex.yy.c: newsearch.l y.tab.h
+       ${LEX} newsearch.l
+
+clean:
+       rm -f *.o *.so y.tab.c y.tab.h lex.yy.c
index 0a7448ee8f260ca7096a93761045a53693ed44bc..bde3ba11a0bbed8e68e1b2665c58e42596d323c6 100644 (file)
@@ -12,6 +12,7 @@
 #include "../lib/strlfunc.h"
 #include "../lib/array.h"
 #include "newsearch.h"
+#include "parser.h"
 
 MODULE_VERSION("");
 
@@ -429,12 +430,16 @@ void newsearch_ctxinit(searchCtx *ctx, searchParseFunc searchfn, replyFunc reply
 
 int do_nicksearch_real(replyFunc reply, wallFunc wall, void *source, int cargc, char **cargv) {
   nick *sender = source;
-  struct searchNode *search;
   int limit=500;
   int arg=0;
   NickDisplayFunc display=defaultnickfn;
-  searchCtx ctx;
   int ret;
+#ifndef NEWSEARCH_NEWPARSER
+  searchCtx ctx;
+  struct searchNode *search;
+#else
+  parsertree *tree;
+#endif
 
   if (cargc<1) {
     reply( sender, "Usage: [flags] <criteria>");
@@ -455,8 +460,8 @@ int do_nicksearch_real(replyFunc reply, wallFunc wall, void *source, int cargc,
     rejoinline(cargv[arg],cargc-arg);
   }
 
+#ifndef NEWSEARCH_NEWPARSER
   newsearch_ctxinit(&ctx, search_parse, reply, wall, NULL, reg_nicksearch, sender, display, limit);
-
   if (!(search = ctx.parser(&ctx, cargv[arg]))) {
     reply(sender,"Parse error: %s",parseError);
     return CMD_ERROR;
@@ -465,6 +470,17 @@ int do_nicksearch_real(replyFunc reply, wallFunc wall, void *source, int cargc,
   nicksearch_exe(search, &ctx);
 
   (search->free)(&ctx, search);
+#else
+  tree = parse_string(reg_nicksearch, cargv[arg]);
+  if(!tree) {
+    reply(sender,"Parse error: %s", parseStrError);
+    return CMD_ERROR;
+  }
+
+  ast_nicksearch(tree->root, reply, sender, wall, display, NULL, NULL, limit);
+
+  parse_free(tree);
+#endif
 
   return CMD_OK;
 }
@@ -521,12 +537,16 @@ void nicksearch_exe(struct searchNode *search, searchCtx *ctx) {
 
 int do_chansearch_real(replyFunc reply, wallFunc wall, void *source, int cargc, char **cargv) {
   nick *sender = source;
-  struct searchNode *search;
   int limit=500;
   int arg=0;
   ChanDisplayFunc display=defaultchanfn;
-  searchCtx ctx;
   int ret;
+#ifndef NEWSEARCH_NEWPARSER
+  struct searchNode *search;
+  searchCtx ctx;
+#else
+  parsertree *tree;
+#endif
 
   if (cargc<1) {
     reply( sender, "Usage: [flags] <criteria>");
@@ -547,6 +567,7 @@ int do_chansearch_real(replyFunc reply, wallFunc wall, void *source, int cargc,
     rejoinline(cargv[arg],cargc-arg);
   }
 
+#ifndef NEWSEARCH_NEWPARSER
   newsearch_ctxinit(&ctx, search_parse, reply, wall, NULL, reg_chansearch, sender, display, limit);
   if (!(search = ctx.parser(&ctx, cargv[arg]))) {
     reply(sender,"Parse error: %s",parseError);
@@ -556,6 +577,17 @@ int do_chansearch_real(replyFunc reply, wallFunc wall, void *source, int cargc,
   chansearch_exe(search, &ctx);
 
   (search->free)(&ctx, search);
+#else
+  tree = parse_string(reg_chansearch, cargv[arg]);
+  if(!tree) {
+    reply(sender,"Parse error: %s", parseStrError);
+    return CMD_ERROR;
+  }
+
+  ast_chansearch(tree->root, reply, sender, wall, display, NULL, NULL, limit);
+
+  parse_free(tree);
+#endif
 
   return CMD_OK;
 }
@@ -592,12 +624,16 @@ void chansearch_exe(struct searchNode *search, searchCtx *ctx) {
 
 int do_usersearch_real(replyFunc reply, wallFunc wall, void *source, int cargc, char **cargv) {
   nick *sender = source;
-  struct searchNode *search;
   int limit=500;
   int arg=0;
   UserDisplayFunc display=defaultuserfn;
-  searchCtx ctx;
   int ret;
+#ifndef NEWSEARCH_NEWPARSER
+  struct searchNode *search;
+  searchCtx ctx;
+#else
+  parsertree *tree;
+#endif
 
   if (cargc<1) {
     reply( sender, "Usage: [flags] <criteria>");
@@ -618,6 +654,7 @@ int do_usersearch_real(replyFunc reply, wallFunc wall, void *source, int cargc,
     rejoinline(cargv[arg],cargc-arg);
   }
 
+#ifndef NEWSEARCH_NEWPARSER
   newsearch_ctxinit(&ctx, search_parse, reply, wall, NULL, reg_usersearch, sender, display, limit);
 
   if (!(search = ctx.parser(&ctx, cargv[arg]))) {
@@ -628,6 +665,17 @@ int do_usersearch_real(replyFunc reply, wallFunc wall, void *source, int cargc,
   usersearch_exe(search, &ctx);
 
   (search->free)(&ctx, search);
+#else
+  tree = parse_string(reg_usersearch, cargv[arg]);
+  if(!tree) {
+    reply(sender,"Parse error: %s", parseStrError);
+    return CMD_ERROR;
+  }
+
+  ast_usersearch(tree->root, reply, sender, wall, display, NULL, NULL, limit);
+
+  parse_free(tree);
+#endif
 
   return CMD_OK;
 }
@@ -929,10 +977,6 @@ static int unescape(char *input, char *output, size_t buflen) {
   return 1;
 }
 
-/* search_parse:
- *  Given an input string, return a searchNode.
- */
-
 struct searchNode *search_parse(searchCtx *ctx, char *cinput) {
   /* OK, we need to split the input into chunks on spaces and brackets.. */
   char *argvector[100];
diff --git a/newsearch/newsearch.l b/newsearch/newsearch.l
new file mode 100644 (file)
index 0000000..fa28c9b
--- /dev/null
@@ -0,0 +1,56 @@
+%option noyywrap
+
+%{
+#include "y.tab.h"
+#include <string.h>
+
+#define YYSTYPE char *
+extern YYSTYPE yylval;
+
+#include <stdlib.h>
+#include "../lib/stringbuf.h"
+
+#define MAX_STR_CONST 512
+%}
+
+digit          [0-9]
+letter         [a-zA-Z]
+
+%x str
+%%
+
+       char bufdata[MAX_STR_CONST];
+       StringBuf buf;
+
+\"             {
+                 sbinit(&buf, bufdata, sizeof(bufdata));
+                 BEGIN(str);
+               }
+
+<str>{
+  \"           {
+                 BEGIN(INITIAL);
+                 sbterminate(&buf);
+                 yylval = strdup(bufdata);
+                 return STRING;
+               }
+  \\\\         { sbaddchar(&buf, '\\');        }
+  \\\"         { sbaddchar(&buf, '"');         }
+  [^\\]                { sbaddchar(&buf, *yytext);     }
+}
+
+"("            { return LPAREN;                }
+")"            { return RPAREN;                }
+[ \t]+         { return WHITESPACE;            }
+{letter}+      {
+                 yylval = strdup(yytext);
+                 return IDENTIFIER;
+               }
+
+[\n\r]         /* ignore */;
+
+<<EOF>>                {
+                 BEGIN(INITIAL);
+                 yyterminate();
+               }
+%%
diff --git a/newsearch/newsearch.y b/newsearch/newsearch.y
new file mode 100644 (file)
index 0000000..7f70dcd
--- /dev/null
@@ -0,0 +1,138 @@
+%{
+#include <stdio.h>
+#include <string.h>
+#include "../lib/stringbuf.h"
+#include "newsearch.h"
+#include "parser.h"
+
+#define YYSTYPE char *
+
+int yylex(void);
+extern char *parseStrError;
+int position;
+
+#define MAXSTACKSIZE 50
+
+typedef struct parserlist {
+  searchASTExpr expr;
+  struct parserlist *next;
+} parserlist;
+
+void yyerror(const char *str) {
+  parseStrError = (char *)str;
+}
+
+static int stackpos;
+static parserlist *stack[MAXSTACKSIZE];
+static int stackcount[MAXSTACKSIZE];
+static fnFinder functionfinder;
+static void *fnfarg;
+static parsertree **presult, sresult;
+
+void resetparser(fnFinder fnf, void *arg, parsertree **result) {
+  presult = result;
+  
+  sresult.exprlist = NULL;
+  sresult.strlist = NULL;
+  sresult.finished = 0;
+  
+  functionfinder = fnf;
+  fnfarg = arg;
+  
+  stackpos = 0;
+}
+
+%}
+
+%token LPAREN RPAREN WHITESPACE IDENTIFIER STRING
+
+%%
+invocation: LPAREN function argumentlist RPAREN
+       {
+    char *str = $2;
+    int i, count;
+    searchASTExpr *ap, *root;
+    parserlist *pp, *npp;
+    expressionlist *xl;
+    parseFunc pfn;
+    
+    stackpos--;
+    count = stackcount[stackpos];
+    
+    pfn = functionfinder(str, fnfarg);
+    if(!pfn) {
+      parse_free(&sresult);
+      YYERROR;
+    }
+    /* if we're at the top of the stack we're the root of the tree */
+    if(stackpos != 0) {
+      /*
+       * we store this function containing its children in the stack list
+       * as there might be functions or other stuff after it, such as:
+       * (fn (fn2) moo moo)
+       */
+      parserlist *rootp = malloc(sizeof(searchASTExpr) + sizeof(parserlist));
+      root = &rootp->expr;
+      
+      stackcount[stackpos-1]++;
+      rootp->next = stack[stackpos-1];
+      stack[stackpos-1] = rootp;
+    } else {
+      /* need space for the final result and real root */
+      *presult = malloc(sizeof(parsertree) + sizeof(searchASTExpr));
+
+      memcpy(*presult, &sresult, sizeof(parsertree));
+      (*presult)->finished = 1;
+      
+      root = (*presult)->root;
+    }
+
+    xl = malloc(sizeof(expressionlist) + sizeof(searchASTExpr) * count);    
+    xl->next = (*presult)->exprlist;
+    (*presult)->exprlist = xl;
+    
+    ap = xl->expr;
+    for(i=count-1,pp=stack[stackpos];i>=0;i--,pp=npp) {
+      npp = pp->next;
+      memcpy(&ap[i], &pp->expr, sizeof(searchASTExpr));
+      free(pp);
+    }
+    *root = NSASTManualNode(pfn, count, ap);
+   
+    free(str);
+       }
+
+function: IDENTIFIER
+  {
+    if(stackpos >= MAXSTACKSIZE - 1)
+      YYERROR;
+      
+    stackcount[stackpos] = 0;
+    stack[stackpos] = NULL;
+    
+    stackpos++;
+  };
+  
+argumentlist: /* empty */ | WHITESPACE argument argumentlist;
+
+argument:
+       invocation | literal
+       {
+    char *str = $1;
+    parserlist *l = malloc(sizeof(parserlist) + sizeof(stringlist));
+    stringlist *sl;
+    
+    l->expr = NSASTLiteral(str);
+    l->next = stack[stackpos - 1];
+    stack[stackpos - 1] = l;
+    stackcount[stackpos - 1]++;
+
+    /* HACK */
+    sl = (stringlist *)(l + 1);
+    
+    sl->next = (*presult)->strlist;
+    (*presult)->strlist = sl;
+       }
+       ;
+
+literal: IDENTIFIER | STRING;
\ No newline at end of file
diff --git a/newsearch/parser.c b/newsearch/parser.c
new file mode 100644 (file)
index 0000000..0ed67a1
--- /dev/null
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include "newsearch.h"
+#include "parser.h"
+
+struct yy_buffer_state;
+
+struct yy_buffer_state *yy_scan_string(const char *);
+void yy_delete_buffer(struct yy_buffer_state *);
+void yy_flush_buffer(struct yy_buffer_state *);
+
+int yyparse(void);
+char *parseStrError;
+
+parseFunc fnfinder(char *name, void *arg) {
+  searchCmd *cmdtree = arg;
+  struct Command *cmd;
+  parseFunc ret;
+  
+  if (!(cmd=findcommandintree(cmdtree->searchtree, name, 1))) {
+    parseError = "Unknown command (for valid command list, see help <searchcmd>)";
+    return NULL;
+  }
+  ret = (parseFunc)cmd->handler;
+  /* TODO */
+  
+  /*
+    if (!controlpermitted(ret->level, ret->sender)) { 
+      parseError = "Access denied (for valid command list, see help <searchcmd>)";
+      return NULL;
+    }
+    return ((parseFunc)cmd->handler)(ctx, j, argvector+1);
+  }*/
+
+  return ret;
+}
+
+parsertree *parse_string(searchCmd *cmd, const char *str) {
+  int ret;
+  struct yy_buffer_state *b;
+  parsertree *pt;
+  
+  b = yy_scan_string(str);
+  if(!b) {
+    parseStrError = "string buffer creation error";
+    return NULL;
+  }
+
+  resetparser(fnfinder, cmd, &pt);
+  ret = yyparse();
+
+  yy_flush_buffer(b);
+  yy_delete_buffer(b);
+
+  if(ret) /* error occured, parseStrError has it */
+    return NULL;
+
+  parseStrError = "not yet implemented";
+  return pt;
+}
+
+void parse_free(parsertree *pt) {
+  stringlist *sl, *nsl;
+  expressionlist *xl, *nxl;
+  
+  for(sl=pt->strlist;sl;sl=nsl) {
+    nsl = sl->next;
+    free(sl);
+  }
+
+  for(xl=pt->exprlist;xl;xl=nxl) {
+    nxl = xl->next;
+    free(xl);
+  }
+  
+  if(pt->finished)
+    free(pt);
+}
diff --git a/newsearch/parser.h b/newsearch/parser.h
new file mode 100644 (file)
index 0000000..0f1f136
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef NEWSEARCH_PARSER_H
+#define NEWSEARCH_PARSER_H
+
+#include "newsearch.h"
+
+typedef struct stringlist {
+  struct stringlist *next;
+  char data[];
+} stringlist;
+
+typedef struct expressionlist {
+  struct expressionlist *next;
+  searchASTExpr expr[];
+} expressionlist;
+
+typedef struct parsertree {
+  expressionlist *exprlist;
+  stringlist *strlist;
+  int finished;
+  searchASTExpr root[];
+} parsertree;
+
+typedef parseFunc (*fnFinder)(char *, void *);
+
+parsertree *parse_string(searchCmd *, const char *);
+void parse_free(parsertree *);
+
+void resetparser(fnFinder fnf, void *arg, parsertree **result);
+
+extern char *parseStrError;
+
+#endif