文章轉自:http://blog.chinaunix.net/uid-20718037-id-4560951.html
前言
用到boa搭建的web服務器,不懂yacc,所以也不明白參數解析原理!
索性就不理解了,退而求其次會用就好了。 看到這一篇有如神助!。
正文
一,
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;
}
-
點擊(此處)摺疊或打開
- %{
- /*
- * Boa, an http server
- * Copyright (C) 1995 Paul Phillips <[email protected]>
- *
- * 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 <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- /* #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 <cval> STMT_NO_ARGS STMT_ONE_ARG STMT_TWO_ARGS
- /* mime.type tokens */
- %token <sval> STRING
- %token <ival> INTEGER
- %token <sval> KEY
- %token <sval> 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);
- }
- ;
- %%
點擊(此處)摺疊或打開
-
/*
-
* 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;
- }
點擊(此處)摺疊或打開
-
/*
-
* 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);
點擊(此處)摺疊或打開
- 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
點擊(此處)摺疊或打開
- 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()函數指定要解析的文件,或將文件名以函數參數的形式傳入,就可以解析指定的文件名中的配置參數。