文章转自: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 <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_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()函数指定要解析的文件,或将文件名以函数参数的形式传入,就可以解析指定的文件名中的配置参数。