一,
boa通过read_config_files()调用语法分析入口函数
yyparse(), 取yyparse()函数调用词法分析入口
函数yylex(),读取并解析boa.conf和mime.types文件, 将其内容理解成一个个的单词,再将每一行单词的组合理解为相应的配置选项。其中yyparse()函数调用yylex()读取boa.conf和mime.types文件内容。具体的,yylex()函数读取文件内容,将文件内容按指定的"词法规则”理解成一个个的单词,并将单词返回给yyparse()函数。yyparse()将得到的单词按指定的"语法规则”理解成配置选项。
二,
yylex()是词法分析入口函数,在lex.yy.c文件中,由"flex boa_lexer.l"命令生成。
flex是词法分析生成工具,boa_lexer.l中的代码指定了"词法规则” 。
yyparse()是语法分析入口函数,在y.tab.c文件中,由"bison -y -d boa_grammar.y"命令生成,
bison是语法分析生成工具,boa_grammar.y中的代码指定了“语法规则” 。
三,
boa_lexer.l文件
boa_lexer.l是flex程序文件,包含三个部分,各部分这间用%%分割。
...定义部分...
%%
...规则部分...
%%
...用户子程序例程...
第一部分是定义部分,包含声明和选项设置。
其中的%{和%}之间的部分会被原样复制到生成的c文件开头部分。是一些头文件包含及宏定义,变量声明等C语言代码
%s和%x用来定义一个包含的起始状态和独占的起始状态。第二部分模式匹配时会用到。
第二部分是规则部分,包含一系列的模式和动作。
其中的模式使用正则表达式语言。动作是模式匹配时执行的C代码。这里的C代码是用{}括住的多行语句或分号";"
第三部分是用户子程序部分,和是则是会被复制到生成的词法分析器里面的C代码。
boa_grammar.y文件
boa_grammar.y是bison程序文件,包含三个部分,各部分这间用%%分割。
..定义部分...
%%
...规则部分...
%%
...用户子程序例程...
第一部分包含声明定义等。
其中的%{和%}之间的部分会被原样复制到目标分析程序开头。%token,%start,%union分别用来声明记号,起始规则,名为YYSTYPE的union类型的域
第二部分
规则部分是一系列的简单BNF定义的规则和动作。
第三部分则是会被复制到生成的语法分析器里面的C代码。
四,代码改造
将代码进行适当修改,成为配置文件解析工具
修改后的代码如下:
1,boa_lexer.l代码
-
%{
-
-
/*
-
* Boa, an http server
-
* Copyright (C) 1995 Paul Phillips <psp@well.com>
-
*
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License as published by
-
* the Free Software Foundation; either version 1, or (at your option)
-
* any later version.
-
*
-
* This program is distributed in the hope that it will be useful,
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
-
*
-
* You should have received a copy of the GNU General Public License
-
* along with this program; if not, write to the Free Software
-
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
*
-
*/
-
-
/* $Id: boa_lexer.l,v 1.13.2.1 2002/07/07 23:19:55 jnelson Exp $*/
-
-
#include "y.tab.h"
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include "parse.h"
-
-
int lineno = 1;
-
struct ccommand *k;
-
char *kptr;
-
%}
-
-
%%
-
-
[ \t]+ ;
-
#.* ;
-
-
[^ \"\t\n]+ { /* XXX could use better checks that we are in a state to
-
* accept keywords; this version matches original behavior */
-
if (k = lookup_keyword(yytext)) {
-
yylval.cval=k;
-
return (k->type);
-
} else { yylval.sval = yytext; return STRING; }
-
}
-
-
\n { lineno++; }
-
%%
-
-
/* In yywrap we track which file we are on.
-
* 1: close boa.conf, open mime.types
-
* 2: return 1;
-
*/
-
-
int yywrap()
-
{
-
fclose(yyin);
-
return 1;
-
}
-
-
int yyerror(char * msg)
-
{
-
fprintf(stderr, "Error on line %d of %s: %s\n", lineno, "boa.conf", msg);
-
return 1;
}
-
2,boa_grammar.y文件代码
-
%{
-
-
/*
-
* Boa, an http server
-
* Copyright (C) 1995 Paul Phillips
-
*
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License as published by
-
* the Free Software Foundation; either version 1, or (at your option)
-
* any later version.
-
*
-
* This program is distributed in the hope that it will be useful,
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
-
*
-
* You should have received a copy of the GNU General Public License
-
* along with this program; if not, write to the Free Software
-
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
*
-
*/
-
-
/* $Id: boa_grammar.y,v 1.14 1999/10/12 14:49:07 jon Exp $*/
-
-
#include
-
#include
-
#include
-
#include
-
/* #include "boa.h" */
-
#include "parse.h"
-
-
int yyerror(char * msg);
-
-
/* yydebug = 1; */
-
-
#ifdef DEBUG
-
#define DBG(x) x
-
#else
-
#define DBG(x)
-
#endif
-
-
char *arg1hold;
-
char mime_type[256]; /* global to inherit */
-
-
%}
-
-
%union {
-
char * sval;
-
int ival;
-
struct ccommand * cval;
-
};
-
-
/* boa.conf tokens */
-
%token STMT_NO_ARGS STMT_ONE_ARG STMT_TWO_ARGS
-
-
/* mime.type tokens */
-
%token STRING
-
%token INTEGER
-
%token KEY
-
%token VALUE
-
-
%start BoaConfigStmts
-
-
%%
-
-
BoaConfigStmts: BoaConfigStmts BoaConfigStmt
-
| /* empty */
-
;
-
-
BoaConfigStmt:
-
StmtNoArgs
-
| StmtOneArg
-
| StmtTwoArgs
-
;
-
-
StmtNoArgs: STMT_NO_ARGS
-
{ if ($1->action) {
-
DBG(printf("StmtNoArgs: %s\n",$1->name);)
-
$1->action(NULL,NULL,$1->object);
-
}
-
}
-
;
-
-
StmtOneArg: STMT_ONE_ARG STRING
-
{ if ($1->action) {
-
DBG(printf("StmtOneArg: %s %s\n",$1->name,$2);)
-
$1->action($2,NULL,$1->object);
-
}
-
}
-
;
-
-
StmtTwoArgs: STMT_TWO_ARGS STRING
-
{ arg1hold = strdup($2); }
-
STRING
-
{ if ($1->action) {
-
DBG(printf("StmtTwoArgs: '%s' '%s' '%s'\n",
-
$1->name,arg1hold,$4);)
-
$1->action($4,arg1hold,$1->object);
-
}
-
free(arg1hold);
-
}
-
;
-
-
%%
3,config.c代码
-
/*
-
* Boa, an http server
-
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
-
*
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License as published by
-
* the Free Software Foundation; either version 1, or (at your option)
-
* any later version.
-
*
-
* This program is distributed in the hope that it will be useful,
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
-
*
-
* You should have received a copy of the GNU General Public License
-
* along with this program; if not, write to the Free Software
-
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
*
-
*/
-
-
/* $Id: config.c,v 1.31.2.3 2002/07/26 03:04:29 jnelson Exp $*/
-
-
#include <string.h>
-
#include <stdlib.h>
-
#include <stdio.h>
-
#include <unistd.h>
-
#include <sys/types.h>
-
#include <pwd.h>
-
#include <grp.h>
-
-
#include "y.tab.h"
-
#include "parse.h"
-
-
int yyparse(void); /* Better match the output of lex */
-
char *mime_types;
-
-
#ifdef DEBUG
-
#define DBG(x) x
-
#else
-
#define DBG(x)
-
#endif
-
-
-
int server_port;
-
uid_t server_uid;
-
gid_t server_gid;
-
char *server_root;
-
char *server_name;
-
char *server_admin;
-
char *server_ip;
-
char *myString;
-
int virtualhost;
-
long int max_connections;
-
-
char *document_root;
-
char *user_dir;
-
char *directory_index;
-
char *default_type;
-
char *dirmaker;
-
char *cachedir;
-
-
char *tempdir;
-
-
char *cgi_path = NULL;
-
int single_post_limit = (1024 * 1024);
-
int verbose_cgi_logs = 0;
-
-
int ka_timeout;
-
int ka_max;
-
int myint;
-
-
int backlog = 250;
-
-
/* These came from log.c */
-
char *error_log_name;
-
char *access_log_name;
-
char *cgi_log_name;
-
-
int use_localtime;
-
-
/* These are new */
-
static void c_set_user(char *v1, char *v2, void *t);
-
static void c_set_group(char *v1, char *v2, void *t);
-
static void c_set_string(char *v1, char *v2, void *t);
-
static void c_set_int(char *v1, char *v2, void *t);
-
static void c_set_unity(char *v1, char *v2, void *t);
-
static void c_add_type(char *v1, char *v2, void *t);
-
static void c_add_alias(char *v1, char *v2, void *t);
-
-
/* Fakery to keep the value passed to action() a void *,
-
see usage in table and c_add_alias() below */
-
static int script_number = 1;
-
static int redirect_number = 2;
-
static int alias_number = 0;
-
static uid_t current_uid=0;
-
-
/* Help keep the table below compact */
-
#define S0A STMT_NO_ARGS
-
#define S1A STMT_ONE_ARG
-
#define S2A STMT_TWO_ARGS
-
-
struct ccommand clist[] = {
-
{"Port", S1A, c_set_int, &server_port},
-
{"Listen", S1A, c_set_string, &server_ip},
-
{"MyString", S1A, c_set_string, &myString},
-
{"BackLog", S1A, c_set_int, &backlog},
-
{"User", S1A, c_set_user, NULL},
-
{"Group", S1A, c_set_group, NULL},
-
{"ServerAdmin", S1A, c_set_string, &server_admin},
-
{"ServerRoot", S1A, c_set_string, &server_root},
-
{"ErrorLog", S1A, c_set_string, &error_log_name},
-
{"AccessLog", S1A, c_set_string, &access_log_name},
-
{"UseLocaltime", S0A, c_set_unity, &use_localtime},
-
{"CgiLog", S1A, c_set_string, &cgi_log_name},
-
{"VerboseCGILogs", S0A, c_set_unity, &verbose_cgi_logs},
-
{"ServerName", S1A, c_set_string, &server_name},
-
{"VirtualHost", S0A, c_set_unity, &virtualhost},
-
{"DocumentRoot", S1A, c_set_string, &document_root},
-
{"UserDir", S1A, c_set_string, &user_dir},
-
{"DirectoryIndex", S1A, c_set_string, &directory_index},
-
{"DirectoryMaker", S1A, c_set_string, &dirmaker},
-
{"DirectoryCache", S1A, c_set_string, &cachedir},
-
{"KeepAliveMax", S1A, c_set_int, &ka_max},
-
{"Myint", S1A, c_set_int, &myint},
-
{"KeepAliveTimeout", S1A, c_set_int, &ka_timeout},
-
{"MimeTypes", S1A, c_set_string, &mime_types},
-
{"DefaultType", S1A, c_set_string, &default_type},
-
{"AddType", S2A, c_add_type, NULL},
-
{"ScriptAlias", S2A, c_add_alias, &script_number},
-
{"Redirect", S2A, c_add_alias, &redirect_number},
-
{"Alias", S2A, c_add_alias, &alias_number},
-
{"SinglePostLimit", S1A, c_set_int, &single_post_limit},
-
{"CGIPath", S1A, c_set_string, &cgi_path},
-
{"MaxConnections", S1A, c_set_int, &max_connections},
-
};
-
-
void printConfig(void)
-
{
-
printf("\n\nserver_port = %d\n", server_port);
-
printf("server_ip = %s\n", server_ip);
-
printf("MyString = %s\n", myString);
-
printf("backlog = %d\n", backlog);
-
printf("server_admin = %s\n", server_admin);
-
printf("server_root = %s\n", server_root);
-
printf("error_log_name = %s\n", error_log_name);
-
printf("access_log_name = %s\n", access_log_name);
-
printf("use_localtime = %d\n", use_localtime);
-
printf("cgi_log_name = %s\n", cgi_log_name);
-
printf("verbose_cgi_logs = %d\n", verbose_cgi_logs);
-
printf("server_name = %s\n", server_name);
-
printf("virtualhost = %d\n", virtualhost);
-
printf("document_root = %s\n", document_root);
-
printf("user_dir = %s\n", user_dir);
-
printf("directory_index = %s\n", directory_index);
-
printf("dirmaker = %s\n", dirmaker);
-
printf("cachedir = %s\n", cachedir);
-
printf("ka_max = %d\n", ka_max);
-
printf("myint = %d\n", myint);
-
printf("ka_timeout = %d\n", ka_timeout);
-
printf("mime_types = %s\n", mime_types);
-
printf("default_type = %s\n", default_type);
-
printf("script_number = %d\n", script_number);
-
printf("redirect_number = %d\n", redirect_number);
-
printf("alias_number = %d\n", alias_number);
-
printf("single_post_limit = %d\n", single_post_limit);
-
printf("cgi_path = %s\n", cgi_path);
-
printf("max_connections = %ld\n", max_connections);
-
}
-
-
void add_mime_type(char *extension, char *type)
-
{
-
}
-
-
void add_alias(char *fakename, char *realname, int type)
-
{
-
}
-
-
static void c_set_user(char *v1, char *v2, void *t)
-
{
-
struct passwd *passwdbuf;
-
char *endptr;
-
int i;
-
-
DBG(printf("User %s = ", v1);
-
)
-
i = strtol(v1, &endptr, 0);
-
if (*v1 != '\0' && *endptr == '\0') {
-
server_uid = i;
-
} else {
-
passwdbuf = getpwnam(v1);
-
if (!passwdbuf) {
-
if (current_uid)
-
return;
-
fprintf(stderr, "No such user: %s\n", v1);
-
exit(1);
-
}
-
server_uid = passwdbuf->pw_uid;
-
}
-
DBG(printf("%d\n", server_uid);
-
)
-
}
-
-
static void c_set_group(char *v1, char *v2, void *t)
-
{
-
struct group *groupbuf;
-
char *endptr;
-
int i;
-
DBG(printf("Group %s = ", v1);
-
)
-
i = strtol(v1, &endptr, 0);
-
if (*v1 != '\0' && *endptr == '\0') {
-
server_gid = i;
-
} else {
-
groupbuf = getgrnam(v1);
-
if (!groupbuf) {
-
if (current_uid)
-
return;
-
fprintf(stderr, "No such group: %s\n", v1);
-
exit(1);
-
}
-
server_gid = groupbuf->gr_gid;
-
}
-
DBG(printf("%d\n", server_gid);
-
)
-
}
-
-
static void c_set_string(char *v1, char *v2, void *t)
-
{
-
char *s;
-
DBG(printf("Setting pointer %p to string %s ..", t, v1);
-
)
-
if (t) {
-
s = *(char **) t;
-
if (s)
-
free(s);
-
*(char **) t = strdup(v1);
-
if (!*(char **) t) {
-
printf("[%s-%d]Unable to strdup in c_set_string", __FILE__, __LINE__);
-
exit(1);
-
}
-
DBG(printf("done.\n");
-
)
-
} else {
-
DBG(printf("skipped.\n");
-
)
-
}
-
}
-
-
static void c_set_int(char *v1, char *v2, void *t)
-
{
-
char *endptr;
-
int i;
-
DBG(printf("Setting pointer %p to integer string %s ..", t, v1);
-
)
-
if (t) {
-
i = strtol(v1, &endptr, 0); /* Automatic base 10/16/8 switching */
-
if (*v1 != '\0' && *endptr == '\0') {
-
*(int *) t = i;
-
DBG(printf(" Integer converted as %d, done\n", i);
-
)
-
} else {
-
/* XXX should tell line number to user */
-
fprintf(stderr, "Error: %s found where integer expected\n",
-
v1);
-
}
-
} else {
-
DBG(printf("skipped.\n");
-
)
-
}
-
}
-
-
static void c_set_unity(char *v1, char *v2, void *t)
-
{
-
DBG(printf("Setting pointer %p to unity\n", t);
-
)
-
if (t)
-
*(int *) t = 1;
-
}
-
-
static void c_add_type(char *v1, char *v2, void *t)
-
{
-
add_mime_type(v1, v2);
-
}
-
-
static void c_add_alias(char *v1, char *v2, void *t)
-
{
-
add_alias(v2, v1, *(int *) t);
-
}
-
-
struct ccommand *lookup_keyword(char *c)
-
{
-
struct ccommand *p;
-
DBG(printf("Checking string '%s' against keyword list\n", c);
-
)
-
for (p = clist;
-
p < clist + (sizeof (clist) / sizeof (struct ccommand)); p++) {
-
if (strcmp(c, p->name) == 0)
-
return p;
-
}
-
return NULL;
-
}
-
-
extern FILE *yyin;
-
int main(int argc, char * argv[])
-
{
-
yyin = fopen("./boa.conf", "r");
-
if (!yyin) {
-
fputs("Could not open boa.conf for reading.\n", stderr);
-
exit(1);
-
}
-
-
yyparse();
-
-
printConfig();
-
return 0;
-
}
4,parse.h
-
/*
-
* Boa, an http server
-
* Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
-
*
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License as published by
-
* the Free Software Foundation; either version 1, or (at your option)
-
* any later version.
-
*
-
* This program is distributed in the hope that it will be useful,
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
-
*
-
* You should have received a copy of the GNU General Public License
-
* along with this program; if not, write to the Free Software
-
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
*
-
* parse.h
-
* minimum interaction point between Boa's parser (boa_lexer.l and
-
* boa_grammar.y) and the rest of Boa.
-
*/
-
-
/* $Id: parse.h,v 1.5 2000/02/12 21:52:45 jon Exp $*/
-
-
struct ccommand {
-
char *name;
-
int type;
-
void (*action) (char *, char *, void *);
-
void *object;
-
};
-
-
struct ckey {
-
char *name;
-
int type;
-
};
-
struct ckey *lookup_key(char *c);
-
struct ccommand *lookup_keyword(char *c);
-
void add_mime_type(char *extension, char *type);
5,测试用的文件boa.conf
-
Port 80
-
User root
-
Group root
-
ErrorLog /dev/console
-
AccessLog /dev/null
-
ServerName zhanglong
-
DocumentRoot /web
-
DirectoryIndex index.html
-
KeepAliveMax 1000
-
Myint 123456
-
KeepAliveTimeout 10
-
MimeTypes /etc/mime.types
-
DefaultType text/plain
-
CGIPath /bin
-
AddType application/x-httpd-cgi cgi
-
MyString valueOfMyString
6,Makefile
-
all:
-
bison -y -d boa_grammar.y
-
#gcc -g -O2 -pipe -Wall -I. -c -o y.tab.o y.tab.c -DDEBUG
-
gcc -g -O2 -pipe -Wall -I. -c -o y.tab.o y.tab.c
-
flex boa_lexer.l
-
gcc -g -O2 -pipe -Wall -I. -c -o lex.yy.o lex.yy.c
-
gcc -g -O2 -pipe -Wall -I. -c -o config.o config.c
-
gcc -o parse y.tab.o lex.yy.o config.o
-
-
clean:
-
rm -f y.tab.c y.tab.h lex.yy.c *.o parse
以上是修改及测试涉及到的全部文件。
五,测试输出及说明
将以上文件置于同一目录下,运行make生成parse可执行文件,输出如下:
然后执行./parse,输出如下:
上面的输出结果中有“MyString = ValueOfMyString”, "myint = 123456"是自己另外加上的。
要添加自己的配置项,只要修改4个地方即可。以添加myint项为例:
1,添加一个全局变量int myint;
2,在struct ccommand clist[]数组中添加一项“ {"Myint", S1A, c_set_int, &myint},”
3,如果要看修改后的结果,在“printConfig()函数”中添加“ printf("myint = %d\n", myint);”
4,在boa.conf文件中添加相应的赋值项。
添加"MyString"项的步骤与添加“myint”的相同,只是myint 是int型数据,在struct ccommand clist[]数组中的赋值函数用c_set_int;而MyString是char *类型,在struct ccommand clist[]数组中的赋值函数用c_set_string。
修改config.c文件main()函数指定要解析的文件,或将文件名以函数参数的形式传入,就可以解析指定的文件名中的配置参数。
阅读(3925) | 评论(0) | 转发(0) |