beginning of obcl. the parser works with semicolons after statements
for now, there is much left to change and do.
This commit is contained in:
parent
69854023a4
commit
7aae14e9b8
7 changed files with 379 additions and 0 deletions
23
obcl/Makefile
Normal file
23
obcl/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
CFLAGS=-ansi -pedantic -Wall `pkg-config --cflags glib-2.0`
|
||||||
|
LIBS=`pkg-config --libs glib-2.0` -ll
|
||||||
|
|
||||||
|
targets = cltest
|
||||||
|
|
||||||
|
sources = obcl.c main.c parse.c lex.c
|
||||||
|
headers = obcl.h
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(targets)
|
||||||
|
|
||||||
|
$(targets): $(sources:.c=.o)
|
||||||
|
$(CC) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
parse.c: parse.y
|
||||||
|
$(YACC) -d -o$@ $^
|
||||||
|
|
||||||
|
lex.c: lex.l
|
||||||
|
$(LEX) -o$@ $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(targets) *.o core *~ lex.c parse.c parse.h
|
21
obcl/foo.conf
Normal file
21
obcl/foo.conf
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
include "meh.conf";
|
||||||
|
include "bummy.conf";
|
||||||
|
|
||||||
|
section mouse {
|
||||||
|
mbind titlebar, frame {
|
||||||
|
event click;
|
||||||
|
button middle;
|
||||||
|
action lower;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbind frame {
|
||||||
|
event click;
|
||||||
|
button right;
|
||||||
|
action launch_nukes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section theme {
|
||||||
|
theme "merry";
|
||||||
|
font "tahoma-12 bold";
|
||||||
|
}
|
86
obcl/lex.l
Normal file
86
obcl/lex.l
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
%{
|
||||||
|
#include "obcl.h"
|
||||||
|
#include "parse.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option yylineno
|
||||||
|
|
||||||
|
DGT [0-9]
|
||||||
|
ID [a-zA-Z_][a-zA-Z_\.\-0-9]*
|
||||||
|
|
||||||
|
|
||||||
|
/* string bummy */
|
||||||
|
%x str
|
||||||
|
%%
|
||||||
|
|
||||||
|
char str_buf[1024];
|
||||||
|
char *str_buf_ptr;
|
||||||
|
int str_char;
|
||||||
|
|
||||||
|
/* begin a string */
|
||||||
|
[\"\'] {
|
||||||
|
str_buf_ptr = str_buf;
|
||||||
|
str_char = yytext[0];
|
||||||
|
BEGIN(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end a string */
|
||||||
|
<str>[\"\'] {
|
||||||
|
if (yytext[0] == str_char) {
|
||||||
|
BEGIN(INITIAL);
|
||||||
|
*str_buf_ptr = '\0';
|
||||||
|
yylval.string = g_strdup(str_buf);
|
||||||
|
return TOK_STRING;
|
||||||
|
} else {
|
||||||
|
*str_buf_ptr++ = yytext[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* can't have newlines in strings */
|
||||||
|
<str>\n {
|
||||||
|
printf("Error: Unterminated string constant.\n");
|
||||||
|
BEGIN(INITIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle \" and \' */
|
||||||
|
<str>"\\"[\"\'] {
|
||||||
|
if (yytext[1] == str_char)
|
||||||
|
*str_buf_ptr++ = yytext[1];
|
||||||
|
else {
|
||||||
|
*str_buf_ptr++ = yytext[0];
|
||||||
|
*str_buf_ptr++ = yytext[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eat valid string contents */
|
||||||
|
<str>[^\\\n\'\"]+ {
|
||||||
|
char *yptr = yytext;
|
||||||
|
while (*yptr) {
|
||||||
|
*str_buf_ptr++ = *yptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* numberz */
|
||||||
|
{DGT}+ {
|
||||||
|
yylval.num = atof(yytext);
|
||||||
|
return TOK_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* real numbers */
|
||||||
|
{DGT}+"."{DGT}* {
|
||||||
|
yylval.num = atof(yytext);
|
||||||
|
return TOK_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* identifiers -- names without spaces and other crap in them */
|
||||||
|
{ID} {
|
||||||
|
yylval.string = g_strdup(yytext);
|
||||||
|
return TOK_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip comments */
|
||||||
|
"#".*\n ;
|
||||||
|
/* skip other whitespace */
|
||||||
|
[ \n\t]+ ;
|
||||||
|
. { return yytext[0]; }
|
||||||
|
%%
|
8
obcl/main.c
Normal file
8
obcl/main.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include "obcl.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
GList *lst = cl_parse("foo.conf");
|
||||||
|
cl_print_tree(lst,0);
|
||||||
|
return 0;
|
||||||
|
}
|
57
obcl/obcl.c
57
obcl/obcl.c
|
@ -0,0 +1,57 @@
|
||||||
|
#include "obcl.h"
|
||||||
|
|
||||||
|
void free_cl_tree(GList *tree)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *cl_parse(gchar *file)
|
||||||
|
{
|
||||||
|
FILE *fh = fopen(file, "r");
|
||||||
|
if (fh)
|
||||||
|
return cl_parse_fh(fh);
|
||||||
|
else {
|
||||||
|
printf("can't open file %s\n", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cl_print_tree(GList *tree, int depth)
|
||||||
|
{
|
||||||
|
CLNode *tmp;
|
||||||
|
int tmpd = depth;
|
||||||
|
|
||||||
|
for (; tree; tree = tree->next) {
|
||||||
|
tmp = (CLNode*)tree->data;
|
||||||
|
|
||||||
|
while (tmpd-- > 0)
|
||||||
|
printf(" ");
|
||||||
|
tmpd = depth;
|
||||||
|
|
||||||
|
switch(tmp->type) {
|
||||||
|
case CL_ID:
|
||||||
|
printf("--ID-- %s\n", tmp->u.str);
|
||||||
|
break;
|
||||||
|
case CL_STR:
|
||||||
|
printf("--STR-- %s\n", tmp->u.str);
|
||||||
|
break;
|
||||||
|
case CL_NUM:
|
||||||
|
printf("--NUM-- %.2f\n", tmp->u.num);
|
||||||
|
break;
|
||||||
|
case CL_LIST:
|
||||||
|
printf("--LIST-- %s\n", tmp->u.lb.id);
|
||||||
|
cl_print_tree(tmp->u.lb.list, depth+2);
|
||||||
|
break;
|
||||||
|
case CL_BLOCK:
|
||||||
|
printf("--BLOCK-- %s\n", tmp->u.lb.id);
|
||||||
|
cl_print_tree(tmp->u.lb.block, depth+2);
|
||||||
|
break;
|
||||||
|
case CL_LISTBLOCK:
|
||||||
|
printf("--LISTBLOCK-- %s\n", tmp->u.lb.id);
|
||||||
|
cl_print_tree(tmp->u.lb.list, depth+2);
|
||||||
|
printf("\n");
|
||||||
|
cl_print_tree(tmp->u.lb.block, depth+2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
obcl/obcl.h
Normal file
38
obcl/obcl.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef __obcl_h
|
||||||
|
#define __obcl_h
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
typedef enum CLNodeType {
|
||||||
|
CL_ID,
|
||||||
|
CL_NUM,
|
||||||
|
CL_STR,
|
||||||
|
CL_LIST,
|
||||||
|
CL_BLOCK,
|
||||||
|
CL_LISTBLOCK
|
||||||
|
} CLNodeType;
|
||||||
|
|
||||||
|
typedef struct CLNode {
|
||||||
|
CLNodeType type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
gchar *id;
|
||||||
|
GList *list;
|
||||||
|
GList *block;
|
||||||
|
} lb;
|
||||||
|
double num;
|
||||||
|
gchar *str;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
} CLNode;
|
||||||
|
|
||||||
|
void free_cl_tree(GList *tree);
|
||||||
|
GList *cl_parse(gchar *file);
|
||||||
|
GList *cl_parse_fh(FILE *file);
|
||||||
|
void cl_print_tree(GList *tree, int depth);
|
||||||
|
|
||||||
|
GList *parse_file(FILE *fh);
|
||||||
|
|
||||||
|
#endif /* __obcl_h */
|
146
obcl/parse.y
Normal file
146
obcl/parse.y
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
%{
|
||||||
|
#include "obcl.h"
|
||||||
|
|
||||||
|
int yylex(void);
|
||||||
|
void yyerror(char *msg, ...);
|
||||||
|
|
||||||
|
extern int yylineno;
|
||||||
|
extern char *yytext;
|
||||||
|
GList *config; /* this is what we parse into */
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%union {
|
||||||
|
double num;
|
||||||
|
gchar *string;
|
||||||
|
CLNode *node;
|
||||||
|
GList *glist;
|
||||||
|
};
|
||||||
|
|
||||||
|
%token <num> TOK_NUM
|
||||||
|
%token <string> TOK_ID TOK_STRING
|
||||||
|
%token TOK_SEP
|
||||||
|
|
||||||
|
%type <glist> config
|
||||||
|
%type <glist> stmts
|
||||||
|
%type <node> stmt
|
||||||
|
%type <glist> list
|
||||||
|
%type <glist> block
|
||||||
|
%type <node> value
|
||||||
|
|
||||||
|
%expect 2 /* for now */
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
config: stmts
|
||||||
|
{
|
||||||
|
config = $$ = $1;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
stmts:
|
||||||
|
{ $$ = NULL; }
|
||||||
|
| stmt
|
||||||
|
{ $$ = g_list_append(NULL, $1); }
|
||||||
|
| stmts stmt
|
||||||
|
{ $$ = g_list_append($1, $2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
stmt: TOK_ID list ';'
|
||||||
|
{
|
||||||
|
CLNode *s = g_new(CLNode,1);
|
||||||
|
s->type = CL_LIST;
|
||||||
|
s->u.lb.list = $2;
|
||||||
|
s->u.lb.id = $1;
|
||||||
|
$$ = s;
|
||||||
|
}
|
||||||
|
| TOK_ID list block
|
||||||
|
{
|
||||||
|
CLNode *s = g_new(CLNode,1);
|
||||||
|
s->type = CL_LISTBLOCK;
|
||||||
|
s->u.lb.list = $2;
|
||||||
|
s->u.lb.block = $3;
|
||||||
|
s->u.lb.id = $1;
|
||||||
|
$$ = s;
|
||||||
|
}
|
||||||
|
| TOK_ID block
|
||||||
|
{
|
||||||
|
CLNode *s = g_new(CLNode,1);
|
||||||
|
s->type = CL_BLOCK;
|
||||||
|
s->u.lb.block = $2;
|
||||||
|
s->u.lb.id = $1;
|
||||||
|
$$ = s;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
list: value
|
||||||
|
{
|
||||||
|
$$ = g_list_append(NULL, $1);
|
||||||
|
}
|
||||||
|
| list ',' value
|
||||||
|
{
|
||||||
|
$$ = g_list_append($1, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
block: '{' stmts '}'
|
||||||
|
{
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
value: TOK_ID
|
||||||
|
{
|
||||||
|
CLNode *node = g_new(CLNode,1);
|
||||||
|
node->type = CL_ID;
|
||||||
|
node->u.str = $1;
|
||||||
|
$$ = node;
|
||||||
|
}
|
||||||
|
| TOK_STRING
|
||||||
|
{
|
||||||
|
CLNode *node = g_new(CLNode,1);
|
||||||
|
node->type = CL_STR;
|
||||||
|
node->u.str = $1;
|
||||||
|
$$ = node;
|
||||||
|
}
|
||||||
|
| TOK_NUM
|
||||||
|
{
|
||||||
|
CLNode *node = g_new(CLNode,1);
|
||||||
|
node->type = CL_NUM;
|
||||||
|
node->u.num = $1;
|
||||||
|
$$ = node;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
int yywrap()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* void yyerror(const char *err) */
|
||||||
|
/* { */
|
||||||
|
/* fprintf(stderr, "Parse error on line %d, near '%s': %s\n", */
|
||||||
|
/* yylineno, yytext, err); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
void yyerror(char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args,msg);
|
||||||
|
|
||||||
|
fprintf(stderr, "Error on line %d, near '%s': ", yylineno, yytext);
|
||||||
|
vfprintf(stderr, msg, args);
|
||||||
|
fprintf(stderr,"\n");
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *cl_parse_fh(FILE *fh)
|
||||||
|
{
|
||||||
|
extern FILE *yyin;
|
||||||
|
yyin = fh;
|
||||||
|
yyparse();
|
||||||
|
return config;
|
||||||
|
}
|
Loading…
Reference in a new issue