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:
Marius Nita 2003-04-14 06:04:49 +00:00
parent 69854023a4
commit 7aae14e9b8
7 changed files with 379 additions and 0 deletions

23
obcl/Makefile Normal file
View 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
View 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
View 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
View file

@ -0,0 +1,8 @@
#include "obcl.h"
int main()
{
GList *lst = cl_parse("foo.conf");
cl_print_tree(lst,0);
return 0;
}

View file

@ -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
View 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
View 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;
}