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