diff --git a/configure.in b/configure.in index a09c93a2..1e2ee098 100644 --- a/configure.in +++ b/configure.in @@ -8,6 +8,8 @@ AM_INIT_AUTOMAKE(mt-daapd,0.1.0) dnl Checks for programs. AC_PROG_CC +AC_PROG_YACC +AC_PROG_LEX AC_CANONICAL_HOST diff --git a/src/Makefile.am b/src/Makefile.am index fdee76a7..1d3ccc1a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,9 @@ # $Id$ # + +BUILT_SOURCES=parser.h +AM_YFLAGS=-d + sbin_PROGRAMS = mt-daapd if COND_REND_POSIX @@ -17,7 +21,8 @@ endif mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \ webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \ daap-proto.c daap-proto.h daap.c daap.h db-memory.c db-memory.h \ - mp3-scanner.h mp3-scanner.c $(RENDSRC) + mp3-scanner.h mp3-scanner.c playlist.c playlist.h \ + lexer.l parser.y $(RENDSRC) EXTRA_DIST = mdns/mDNS.c mdns/mDNSClientAPI.h mdns/mDNSDebug.h mdns/mDNSPosix.c \ mdns/mDNSUNP.c rend-howl.c rend-posix.c rend-osx.c diff --git a/src/lexer.l b/src/lexer.l new file mode 100644 index 00000000..50c9189d --- /dev/null +++ b/src/lexer.l @@ -0,0 +1,84 @@ +%{ + +/* $Id$ + * + * Simple playlist lexer + */ + +#include + +#include "playlist.h" +#include "parser.h" + +extern int yydebug; + +%} + +%option yylineno + +%% + +[\n\t ]+ + +artist { yylval.ival=TOK_ARTIST; return(TOK_ARTIST); } +album { yylval.ival=TOK_ALBUM; return(TOK_ALBUM); } +genre { yylval.ival=TOK_GENRE; return(TOK_GENRE); } + +is | += { yylval.ival=TOK_IS; return(TOK_IS); } + +includes | +=~ | +~= { yylval.ival=TOK_INCLUDES; return(TOK_INCLUDES); } + +or | +\|\| { yylval.ival=TOK_OR; return(TOK_OR); } + +and | +&& { yylval.ival=TOK_AND; return(TOK_AND); } + +not | +! { yylval.ival=1; return(TOK_NOT); } + + +\"[A-Za-z0-9 ]*\" { yylval.cval=strdup(yytext); return(TOK_ID); } + +. { return yytext[0]; } + +%% + +int yywrap(void) { + return 1; +} + +void yyerror(char *msg) { + printf("\nParser Error: Line %d: %s\n",yylineno, msg); + printf("Wish I could be more helpful. :(\n\n"); + printf("If you know how to generate good yacc errors, please\n"); + printf("Let me know!\n\n"); + exit(0); +} + + +/* +int main(int argc, char *argv[]) { + FILE *fin; + int result; + + yydebug=1; + + fin=fopen(argv[1],"r"); + if(!fin) { + perror("fopen"); + return 1; + } + + yyin=fin; + result=yyparse(); + printf("Parsed... result = %d\n", result); + + pl_dump(); + + return 0; +} +*/ diff --git a/src/parser.y b/src/parser.y new file mode 100644 index 00000000..cbf4a397 --- /dev/null +++ b/src/parser.y @@ -0,0 +1,116 @@ +%{ + +#include +#include "playlist.h" + +#define YYERROR_VERBOSE 1 + +/* Forwards */ + +extern PL_NODE *pl_newpredicate(int tag, int op, char *value); +extern PL_NODE *pl_newexpr(PL_NODE *arg1, int op, PL_NODE *arg2); +extern int pl_addplaylist(char *name, PL_NODE *root); + +%} + +%left TOK_OR TOK_AND + +%union { + unsigned int ival; + char *cval; + PL_NODE *plval; +} + +%token TOK_ARTIST +%token TOK_ALBUM +%token TOK_GENRE + +%token TOK_IS +%token TOK_INCLUDES + +%token TOK_OR +%token TOK_AND +%token TOK_NOT + +%token TOK_ID + +%type expression +%type predicate +%type idtag +%type boolarg +%type value +%type playlist + +%% + +playlistlist: playlist +| playlistlist playlist +; + +playlist: TOK_ID '{' expression '}' { $$ = pl_addplaylist($1, $3); } +; + +expression: expression TOK_AND expression { $$=pl_newexpr($1,$2,$3); } +| expression TOK_OR expression { $$=pl_newexpr($1,$2,$3); } +| '(' expression ')' { $$=$2; } +| predicate +; + +predicate: idtag boolarg value { $$=pl_newpredicate($1, $2, $3); } + +idtag: TOK_ARTIST +| TOK_ALBUM +| TOK_GENRE +; + +boolarg: TOK_IS +| TOK_INCLUDES +| TOK_NOT boolarg { $$=$2 | 0x80000000; } +; + +value: TOK_ID +; + + +%% + +PL_NODE *pl_newpredicate(int tag, int op, char *value) { + PL_NODE *pnew; + + pnew=(PL_NODE*)malloc(sizeof(PL_NODE)); + if(!pnew) + return NULL; + + pnew->op=op; + pnew->arg1.ival=tag; + pnew->arg2.cval=value; + return pnew; +} + +PL_NODE *pl_newexpr(PL_NODE *arg1, int op, PL_NODE *arg2) { + PL_NODE *pnew; + + pnew=(PL_NODE*)malloc(sizeof(PL_NODE)); + if(!pnew) + return NULL; + + pnew->op=op; + pnew->arg1.plval=arg1; + pnew->arg2.plval=arg2; + return pnew; +} + +int pl_addplaylist(char *name, PL_NODE *root) { + SMART_PLAYLIST *pnew; + + pnew=(SMART_PLAYLIST *)malloc(sizeof(SMART_PLAYLIST)); + if(!pnew) + return -1; + + pnew->next=pl_smart.next; + pnew->name=name; + pnew->root=root; + pl_smart.next=pnew; + + return 0; +} diff --git a/src/playlist.c b/src/playlist.c new file mode 100644 index 00000000..0e1c64e3 --- /dev/null +++ b/src/playlist.c @@ -0,0 +1,92 @@ +/* + * $Id$ + * + */ + +#include + +#include "playlist.h" +#include "parser.h" + +/* Globals */ +SMART_PLAYLIST pl_smart = { NULL, NULL, NULL }; + +/* Forwards */ +void pl_dump(void); +void pl_dump_node(PL_NODE *pnode, int indent); + +/* + * pl_dump + * + * Dump the playlist list for debugging + */ +void pl_dump(void) { + SMART_PLAYLIST *pcurrent=pl_smart.next; + + while(pcurrent) { + printf("Playlist %s:\n",pcurrent->name); + pl_dump_node(pcurrent->root,1); + pcurrent=pcurrent->next; + } +} + +/* + * pl_dump_node + * + * recursively dump a node + */ +void pl_dump_node(PL_NODE *pnode, int indent) { + int index; + int not=0; + unsigned int boolarg; + + for(index=0;indexop == TOK_AND) { + printf("AND\n"); + } else if (pnode->op == TOK_OR) { + printf("OR\n"); + } + + if((pnode->op == TOK_AND) || (pnode->op == TOK_OR)) { + pl_dump_node(pnode->arg1.plval,indent+1); + pl_dump_node(pnode->arg2.plval,indent+1); + return; + } + + switch(pnode->arg1.ival) { + case TOK_ARTIST: + printf("ARTIST "); + break; + case TOK_ALBUM: + printf("ALBUM "); + break; + case TOK_GENRE: + printf("GENRE "); + break; + default: + printf (" "); + break; + } + + boolarg=(pnode->op) & 0x7FFFFFFF; + if(pnode->op & 0x80000000) + not=1; + + switch(boolarg) { + case TOK_IS: + printf("%s",not? "IS " : "IS NOT "); + break; + case TOK_INCLUDES: + printf("%s",not? "INCLUDES " : "DOES NOT INCLUDE "); + break; + default: + printf(" "); + break; + } + + printf("%s\n",pnode->arg2.cval); + return; +} diff --git a/src/playlist.h b/src/playlist.h new file mode 100644 index 00000000..7526388a --- /dev/null +++ b/src/playlist.h @@ -0,0 +1,32 @@ +/* + * $Id$ + * + */ + +#ifndef _PL_H_ +#define _PL_H_ + +typedef struct tag_pl_node { + int op; + union { + int ival; + struct tag_pl_node *plval; + } arg1; + union { + char *cval; + struct tag_pl_node *plval; + } arg2; +} PL_NODE; + +typedef struct tag_smart_playlist { + char *name; + PL_NODE *root; + struct tag_smart_playlist *next; +} SMART_PLAYLIST; + +extern SMART_PLAYLIST pl_smart; +extern void pl_dump(void); + +#endif /* _PL_H_ */ + +