yacc解析conf
my.conf
globals {
name XXX;
home XXX;
ok on;
health {
good;
}
}
other {
iqn iqn.2015-10-10.com.name;
}
Makefile
FLEX = flex
YACC = bison
YFLAGS = -d
CC = gcc
BUILT_SOURCES = confl.c confy.c confy.h
CONFIGURE_SOURCE = configure.c configure.h
TEST_SOURCE = test.c
TARGET = test
$(TARGET):lex
$(CC) -o $@ $(TEST_SOURCE) $(BUILT_SOURCES) $(CONFIGURE_SOURCE)
lex:yacc
$(FLEX) -o confl.c confl.l
yacc:
$(YACC) -o confy.c -d confy.y
.PHONY:clean
clean:
-rm -f confl.c confy.c confy.h $(TARGET)
test.c
#include <stdio.h>
#include "configure.h"
int main(int argc, char *argv[])
{
conf_init();
printf("name: %s\n", glo_conf.name);
conf_destroy();
return 0;
}
configure.c
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "configure.h"
#include "confy.h"
extern FILE *yyin;
int line = 1;
healthconf_t health_conf;
struct otherconf_t other_conf;
struct gloconf_t glo_conf;
static char config_path[MAXSIZE];
int get_health(const char *health)
{
if (health != NULL) {
strncpy(health_conf.health, health, MAXSIZE);
health_conf.count++;
}
return 0;
}
void yyerror(const char *str)
{
fprintf(stderr, "config: parse %s error at line %d, %s\n",
config_path, line, str);
exit(1);
}
int yywrap() {
return 1;
}
extern int yyparse();
int conf_init()
{
int ret;
char cwd[MAXSIZE];
getcwd(cwd, MAXSIZE);
snprintf(config_path, MAXSIZE, "%s/my.conf", cwd);
/* default */
memset(glo_conf.name, 0x0, MAXSIZE);
strcpy(glo_conf.name, "none");
strcpy(other_conf.iqn, "none");
glo_conf.ok = 1;
memset(health_conf.health, 0x0, MAXSIZE);
strcpy(health_conf.health, "none");
health_conf.count = 0;
yyin = fopen(config_path, "r");
if (yyin == NULL) {
ret = errno;
fprintf(stderr, "open %s fail, ret %u\n", config_path, ret);
goto err_ret;
}
yyparse();
return 0;
err_ret:
return ret;
}
int conf_destroy(void)
{
fclose(yyin);
return 0;
}
LLU str2val(const char *str)
{
LLU val;
val = atoll(str);
return val;
}
int keyis(const char *src, const char *dst)
{
int dstlen;
dstlen = strlen(dst);
if (strncmp(src, dst, dstlen) == 0)
return 1;
else
return 0;
}
int set_value(const char* key, const char* value, int type)
{
int vallen;
LLU _value;
vallen = strlen(value);
if (type == V_NUMBER)
_value = str2val(value);
else if (type == V_STATE) {
if (strncasecmp("on", value, vallen) == 0)
_value = 1;
else
_value = 0;
}
/**
* other configure
*/
else if (keyis("iqn", key))
strncpy(other_conf.iqn, value, MAXSIZE);
else if (keyis("health", key)) {
strncpy(health_conf.health, value, MAXSIZE);
health_conf.count++;
}
/**
* global configure
*/
else if (keyis("name", key))
strncpy(glo_conf.name, value, MAXSIZE);
else if (keyis("home", key))
strncpy(glo_conf.home, value, MAXSIZE);
else if (keyis("ok", key))
glo_conf.ok = _value;
/**
* error.
*/
else {
fprintf(stderr, "%s:%s no such key_value\n", key, value);
}
return 0;
}
configure.h
#ifndef __CONFIGURE_H__
#define __CONFIGURE_H__
#include <stdint.h>
#define MAXSIZE 256
typedef unsigned long long LLU;
enum value_type {
V_STATE,
V_NUMBER,
V_STRING,
};
typedef struct {
int count;
char health[MAXSIZE];
}healthconf_t;
/* other configure */
struct otherconf_t
{
char iqn[MAXSIZE];
};
/* global configure */
struct gloconf_t
{
char name[MAXSIZE];
char home[MAXSIZE];
int ok;
};
extern int conf_init(void);
extern int conf_destroy(void);
extern healthconf_t health_conf;
extern struct otherconf_t other_conf;
extern struct gloconf_t glo_conf;
#endif
confl.l
%{
#include <stdio.h>
#include "configure.h"
#include "confy.h"
extern int line;
%}
%%
"globals" { return GLOBALS; }
"other" { return OTHER; }
"health" {
yylval.string = strdup(yytext);
return HEALTH;
}
"on" {
yylval.string = strdup(yytext);
return STATE;
}
"of" {
yylval.string = strdup(yytext);
return STATE;
}
[0-9]+ {
yylval.string = strdup(yytext);
return NUMBER;
}
[a-zA-Z0-9_]{0,512} {
yylval.string = strdup(yytext);
return WORD;
}
iqn\.[0-9]{4}\-[0-9]{2}(\-[0-9]{1,4})?\.com\.[a-zA-Z0-9_]+ {
yylval.string = strdup(yytext);
return IQN;
}
[()] { return *yytext; }
\{ { return OBRACE; }
\} { return EBRACE; }
\n { line++; }
; { return SEMICOLON; }
[ \r\t]+ /** ignore whitespace */
\#[^\n]* /** ignore comment */
. {
fprintf(stderr, "unkonw char %c\n", *yytext);
return 0;
}
%%
confy.y
%{
#include <stdio.h>
#include "configure.h"
extern int yylex(void);
extern void yyerror(char *s);
extern int get_health(const char *health);
extern int set_value(const char* key, const char* value, int type);
%}
%defines
%union {
double value;
char *string;
}
%token OTHER GLOBALS SEMICOLON OBRACE EBRACE
%token <string> HEALTH
%token <string> WORD
%token <string> STATE
%token <string> NUMBER
%token <string> IQN
%start conf
%%
conf: subapps
;
subapps: subapp
| subapps subapp
;
subapp: app app_subsets
;
app: OTHER
| GLOBALS
;
app_subsets: OBRACE local_values sub_values EBRACE
;
local_values:
| local_values local_value
;
local_value: key_value SEMICOLON
;
sub_values:
| sub_value sub_values
;
// sub
sub_value: healths_value
;
healths_value: HEALTH OBRACE healths_lines EBRACE
;
healths_lines: healths_line
| healths_lines healths_line
;
healths_line: WORD SEMICOLON {
get_health($1);
free($1);
}
;
key_value: WORD NUMBER {
set_value($1, $2, V_NUMBER);
free($1);
free($2);
}
;
key_value: WORD WORD {
set_value($1, $2, V_STRING);
free($1);
free($2);
}
;
key_value: WORD STATE {
set_value($1, $2, V_STATE);
free($1);
free($2);
}
;
key_value: WORD IQN {
set_value($1, $2, V_STRING);
free($1);
free($2);
}
;
%%
posted on 2015-10-10 17:43 DayAfterDay 阅读(220) 评论(0) 编辑 收藏 举报