Chinaunix首页 | 论坛 | 博客
  • 博客访问: 698808
  • 博文数量: 193
  • 博客积分: 1875
  • 博客等级: 上尉
  • 技术积分: 2187
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-23 23:21
个人简介

有时候,就是想窥视一下不知道的东东,因为好奇!

文章分类

全部博文(193)

文章存档

2024年(9)

2023年(3)

2020年(1)

2019年(1)

2018年(1)

2017年(2)

2016年(69)

2015年(53)

2014年(14)

2013年(1)

2012年(5)

2011年(25)

2010年(9)

分类: LINUX

2014-10-19 18:39:34

一,
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代码  

点击(此处)折叠或打开

  1. %{

  2. /*
  3.  * Boa, an http server
  4.  * Copyright (C) 1995 Paul Phillips <psp@well.com>
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  */

  21. /* $Id: boa_lexer.l,v 1.13.2.1 2002/07/07 23:19:55 jnelson Exp $*/

  22. #include "y.tab.h"
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include "parse.h"

  26. int lineno = 1;
  27. struct ccommand *k;
  28. char *kptr;
  29. %}

  30. %%

  31. [ \t]+        ;
  32. #.*        ;

  33. [^ \"\t\n]+    { /* XXX could use better checks that we are in a state to
  34.          * accept keywords; this version matches original behavior */
  35.          if (k = lookup_keyword(yytext)) {
  36.          yylval.cval=k;
  37.          return (k->type);
  38.          } else { yylval.sval = yytext; return STRING; }
  39.             }

  40. \n        { lineno++; }
  41. %%

  42. /* In yywrap we track which file we are on.
  43.  * 1: close boa.conf, open mime.types
  44.  * 2: return 1;
  45.  */

  46. int yywrap()
  47. {
  48.     fclose(yyin);
  49.     return 1;
  50. }

  51. int yyerror(char * msg)
  52. {
  53.     fprintf(stderr, "Error on line %d of %s: %s\n", lineno, "boa.conf", msg); 
  54.     return 1;
    }

   2,boa_grammar.y文件代码

点击(此处)折叠或打开

  1. %{
  2. /*
  3. * Boa, an http server
  4. * Copyright (C) 1995 Paul Phillips
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 1, or (at your option)
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. */
  21. /* $Id: boa_grammar.y,v 1.14 1999/10/12 14:49:07 jon Exp $*/
  22. #include
  23. #include
  24. #include
  25. #include
  26. /* #include "boa.h" */
  27. #include "parse.h"
  28. int yyerror(char * msg);
  29. /* yydebug = 1; */
  30. #ifdef DEBUG
  31. #define DBG(x) x
  32. #else
  33. #define DBG(x)
  34. #endif
  35. char *arg1hold;
  36. char mime_type[256]; /* global to inherit */
  37. %}
  38. %union {
  39. char * sval;
  40. int ival;
  41. struct ccommand * cval;
  42. };
  43. /* boa.conf tokens */
  44. %token STMT_NO_ARGS STMT_ONE_ARG STMT_TWO_ARGS
  45. /* mime.type tokens */
  46. %token STRING
  47. %token INTEGER
  48. %token KEY
  49. %token VALUE
  50. %start BoaConfigStmts
  51. %%
  52. BoaConfigStmts: BoaConfigStmts BoaConfigStmt
  53. | /* empty */
  54. ;
  55. BoaConfigStmt:
  56. StmtNoArgs
  57. | StmtOneArg
  58. | StmtTwoArgs
  59. ;
  60. StmtNoArgs: STMT_NO_ARGS
  61. { if ($1->action) {
  62. DBG(printf("StmtNoArgs: %s\n",$1->name);)
  63. $1->action(NULL,NULL,$1->object);
  64. }
  65. }
  66. ;
  67. StmtOneArg: STMT_ONE_ARG STRING
  68. { if ($1->action) {
  69. DBG(printf("StmtOneArg: %s %s\n",$1->name,$2);)
  70. $1->action($2,NULL,$1->object);
  71. }
  72. }
  73. ;
  74. StmtTwoArgs: STMT_TWO_ARGS STRING
  75. { arg1hold = strdup($2); }
  76. STRING
  77. { if ($1->action) {
  78. DBG(printf("StmtTwoArgs: '%s' '%s' '%s'\n",
  79. $1->name,arg1hold,$4);)
  80. $1->action($4,arg1hold,$1->object);
  81. }
  82. free(arg1hold);
  83. }
  84. ;
  85. %%
3,config.c代码
  

点击(此处)折叠或打开

  1. /*
  2.  * Boa, an http server
  3.  * Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 1, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */

  20. /* $Id: config.c,v 1.31.2.3 2002/07/26 03:04:29 jnelson Exp $*/

  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <unistd.h>
  25. #include <sys/types.h>
  26. #include <pwd.h>
  27. #include <grp.h>

  28. #include "y.tab.h"
  29. #include "parse.h"

  30. int yyparse(void); /* Better match the output of lex */
  31. char *mime_types;

  32. #ifdef DEBUG
  33. #define DBG(x) x
  34. #else
  35. #define DBG(x)
  36. #endif


  37. int server_port;
  38. uid_t server_uid;
  39. gid_t server_gid;
  40. char *server_root;
  41. char *server_name;
  42. char *server_admin;
  43. char *server_ip;
  44. char *myString;
  45. int virtualhost;
  46. long int max_connections;

  47. char *document_root;
  48. char *user_dir;
  49. char *directory_index;
  50. char *default_type;
  51. char *dirmaker;
  52. char *cachedir;

  53. char *tempdir;

  54. char *cgi_path = NULL;
  55. int single_post_limit = (1024 * 1024);
  56. int verbose_cgi_logs = 0;

  57. int ka_timeout;
  58. int ka_max;
  59. int myint;

  60. int backlog = 250;

  61. /* These came from log.c */
  62. char *error_log_name;
  63. char *access_log_name;
  64. char *cgi_log_name;

  65. int use_localtime;

  66. /* These are new */
  67. static void c_set_user(char *v1, char *v2, void *t);
  68. static void c_set_group(char *v1, char *v2, void *t);
  69. static void c_set_string(char *v1, char *v2, void *t);
  70. static void c_set_int(char *v1, char *v2, void *t);
  71. static void c_set_unity(char *v1, char *v2, void *t);
  72. static void c_add_type(char *v1, char *v2, void *t);
  73. static void c_add_alias(char *v1, char *v2, void *t);

  74. /* Fakery to keep the value passed to action() a void *,
  75.    see usage in table and c_add_alias() below */
  76. static int script_number = 1;
  77. static int redirect_number = 2;
  78. static int alias_number = 0;
  79. static uid_t current_uid=0;

  80. /* Help keep the table below compact */
  81. #define S0A STMT_NO_ARGS
  82. #define S1A STMT_ONE_ARG
  83. #define S2A STMT_TWO_ARGS

  84. struct ccommand clist[] = {
  85.     {"Port", S1A, c_set_int, &server_port},
  86.     {"Listen", S1A, c_set_string, &server_ip},
  87.     {"MyString", S1A, c_set_string, &myString},
  88.     {"BackLog", S1A, c_set_int, &backlog},
  89.     {"User", S1A, c_set_user, NULL},
  90.     {"Group", S1A, c_set_group, NULL},
  91.     {"ServerAdmin", S1A, c_set_string, &server_admin},
  92.     {"ServerRoot", S1A, c_set_string, &server_root},
  93.     {"ErrorLog", S1A, c_set_string, &error_log_name},
  94.     {"AccessLog", S1A, c_set_string, &access_log_name},
  95.     {"UseLocaltime", S0A, c_set_unity, &use_localtime},
  96.     {"CgiLog", S1A, c_set_string, &cgi_log_name},
  97.     {"VerboseCGILogs", S0A, c_set_unity, &verbose_cgi_logs},
  98.     {"ServerName", S1A, c_set_string, &server_name},
  99.     {"VirtualHost", S0A, c_set_unity, &virtualhost},
  100.     {"DocumentRoot", S1A, c_set_string, &document_root},
  101.     {"UserDir", S1A, c_set_string, &user_dir},
  102.     {"DirectoryIndex", S1A, c_set_string, &directory_index},
  103.     {"DirectoryMaker", S1A, c_set_string, &dirmaker},
  104.     {"DirectoryCache", S1A, c_set_string, &cachedir},
  105.     {"KeepAliveMax", S1A, c_set_int, &ka_max},
  106.     {"Myint", S1A, c_set_int, &myint},
  107.     {"KeepAliveTimeout", S1A, c_set_int, &ka_timeout},
  108.     {"MimeTypes", S1A, c_set_string, &mime_types},
  109.     {"DefaultType", S1A, c_set_string, &default_type},
  110.     {"AddType", S2A, c_add_type, NULL},
  111.     {"ScriptAlias", S2A, c_add_alias, &script_number},
  112.     {"Redirect", S2A, c_add_alias, &redirect_number},
  113.     {"Alias", S2A, c_add_alias, &alias_number},
  114.     {"SinglePostLimit", S1A, c_set_int, &single_post_limit},
  115.     {"CGIPath", S1A, c_set_string, &cgi_path},
  116.     {"MaxConnections", S1A, c_set_int, &max_connections},
  117. };

  118. void printConfig(void)
  119. {
  120.     printf("\n\nserver_port = %d\n", server_port);
  121.     printf("server_ip = %s\n", server_ip);
  122.     printf("MyString = %s\n", myString);
  123.     printf("backlog = %d\n", backlog);
  124.     printf("server_admin = %s\n", server_admin);
  125.     printf("server_root = %s\n", server_root);
  126.     printf("error_log_name = %s\n", error_log_name);
  127.     printf("access_log_name = %s\n", access_log_name);
  128.     printf("use_localtime = %d\n", use_localtime);
  129.     printf("cgi_log_name = %s\n", cgi_log_name);
  130.     printf("verbose_cgi_logs = %d\n", verbose_cgi_logs);
  131.     printf("server_name = %s\n", server_name);
  132.     printf("virtualhost = %d\n", virtualhost);
  133.     printf("document_root = %s\n", document_root);
  134.     printf("user_dir = %s\n", user_dir);
  135.     printf("directory_index = %s\n", directory_index);
  136.     printf("dirmaker = %s\n", dirmaker);
  137.     printf("cachedir = %s\n", cachedir);
  138.     printf("ka_max = %d\n", ka_max);
  139.     printf("myint = %d\n", myint);
  140.     printf("ka_timeout = %d\n", ka_timeout);
  141.     printf("mime_types = %s\n", mime_types);
  142.     printf("default_type = %s\n", default_type);
  143.     printf("script_number = %d\n", script_number);
  144.     printf("redirect_number = %d\n", redirect_number);
  145.     printf("alias_number = %d\n", alias_number);
  146.     printf("single_post_limit = %d\n", single_post_limit);
  147.     printf("cgi_path = %s\n", cgi_path);
  148.     printf("max_connections = %ld\n", max_connections);
  149. }

  150. void add_mime_type(char *extension, char *type)
  151. {
  152. }

  153. void add_alias(char *fakename, char *realname, int type)
  154. {
  155. }

  156. static void c_set_user(char *v1, char *v2, void *t)
  157. {
  158.     struct passwd *passwdbuf;
  159.     char *endptr;
  160.     int i;

  161.     DBG(printf("User %s = ", v1);
  162.         )
  163.         i = strtol(v1, &endptr, 0);
  164.     if (*v1 != '\0' && *endptr == '\0') {
  165.         server_uid = i;
  166.     } else {
  167.         passwdbuf = getpwnam(v1);
  168.         if (!passwdbuf) {
  169.             if (current_uid)
  170.                 return;
  171.             fprintf(stderr, "No such user: %s\n", v1);
  172.             exit(1);
  173.         }
  174.         server_uid = passwdbuf->pw_uid;
  175.     }
  176.     DBG(printf("%d\n", server_uid);
  177.         )
  178. }

  179. static void c_set_group(char *v1, char *v2, void *t)
  180. {
  181.     struct group *groupbuf;
  182.     char *endptr;
  183.     int i;
  184.     DBG(printf("Group %s = ", v1);
  185.         )
  186.         i = strtol(v1, &endptr, 0);
  187.     if (*v1 != '\0' && *endptr == '\0') {
  188.         server_gid = i;
  189.     } else {
  190.         groupbuf = getgrnam(v1);
  191.         if (!groupbuf) {
  192.             if (current_uid)
  193.                 return;
  194.             fprintf(stderr, "No such group: %s\n", v1);
  195.             exit(1);
  196.         }
  197.         server_gid = groupbuf->gr_gid;
  198.     }
  199.     DBG(printf("%d\n", server_gid);
  200.         )
  201. }

  202. static void c_set_string(char *v1, char *v2, void *t)
  203. {
  204.     char *s;
  205.     DBG(printf("Setting pointer %p to string %s ..", t, v1);
  206.         )
  207.         if (t) {
  208.         s = *(char **) t;
  209.         if (s)
  210.             free(s);
  211.         *(char **) t = strdup(v1);
  212.         if (!*(char **) t) {
  213.             printf("[%s-%d]Unable to strdup in c_set_string", __FILE__, __LINE__);
  214.             exit(1);
  215.         }
  216.         DBG(printf("done.\n");
  217.             )
  218.     } else {
  219.         DBG(printf("skipped.\n");
  220.             )
  221.     }
  222. }

  223. static void c_set_int(char *v1, char *v2, void *t)
  224. {
  225.     char *endptr;
  226.     int i;
  227.     DBG(printf("Setting pointer %p to integer string %s ..", t, v1);
  228.         )
  229.         if (t) {
  230.         i = strtol(v1, &endptr, 0); /* Automatic base 10/16/8 switching */
  231.         if (*v1 != '\0' && *endptr == '\0') {
  232.             *(int *) t = i;
  233.             DBG(printf(" Integer converted as %d, done\n", i);
  234.                 )
  235.         } else {
  236.             /* XXX should tell line number to user */
  237.             fprintf(stderr, "Error: %s found where integer expected\n",
  238.                     v1);
  239.         }
  240.     } else {
  241.         DBG(printf("skipped.\n");
  242.             )
  243.     }
  244. }

  245. static void c_set_unity(char *v1, char *v2, void *t)
  246. {
  247.     DBG(printf("Setting pointer %p to unity\n", t);
  248.         )
  249.         if (t)
  250.         *(int *) t = 1;
  251. }

  252. static void c_add_type(char *v1, char *v2, void *t)
  253. {
  254.     add_mime_type(v1, v2);
  255. }

  256. static void c_add_alias(char *v1, char *v2, void *t)
  257. {
  258.     add_alias(v2, v1, *(int *) t);
  259. }

  260. struct ccommand *lookup_keyword(char *c)
  261. {
  262.     struct ccommand *p;
  263.     DBG(printf("Checking string '%s' against keyword list\n", c);
  264.         )
  265.         for (p = clist;
  266.              p < clist + (sizeof (clist) / sizeof (struct ccommand)); p++) {
  267.         if (strcmp(c, p->name) == 0)
  268.             return p;
  269.     }
  270.     return NULL;
  271. }

  272. extern FILE *yyin;
  273. int main(int argc, char * argv[])
  274. {
  275.     yyin = fopen("./boa.conf", "r");
  276.     if (!yyin) {
  277.         fputs("Could not open boa.conf for reading.\n", stderr);
  278.         exit(1);
  279.     }

  280.     yyparse();

  281.     printConfig();
  282.     return 0;
  283. }
4,parse.h

点击(此处)折叠或打开

  1. /*
  2.  * Boa, an http server
  3.  * Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 1, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  * parse.h
  20.  * minimum interaction point between Boa's parser (boa_lexer.l and
  21.  * boa_grammar.y) and the rest of Boa.
  22.  */

  23. /* $Id: parse.h,v 1.5 2000/02/12 21:52:45 jon Exp $*/

  24. struct ccommand {
  25.     char *name;
  26.     int type;
  27.     void (*action) (char *, char *, void *);
  28.     void *object;
  29. };

  30. struct ckey {
  31.     char *name;
  32.     int type;
  33. };
  34. struct ckey *lookup_key(char *c);
  35. struct ccommand *lookup_keyword(char *c);
  36. void add_mime_type(char *extension, char *type);
5,测试用的文件boa.conf
    

点击(此处)折叠或打开

  1. Port 80
  2. User root
  3. Group root
  4. ErrorLog /dev/console
  5. AccessLog /dev/null
  6. ServerName zhanglong
  7. DocumentRoot /web
  8. DirectoryIndex index.html
  9. KeepAliveMax 1000
  10. Myint 123456
  11. KeepAliveTimeout 10
  12. MimeTypes /etc/mime.types
  13. DefaultType text/plain
  14. CGIPath /bin
  15. AddType application/x-httpd-cgi cgi
  16. MyString valueOfMyString
6,Makefile
   

点击(此处)折叠或打开

  1. all:
  2. bison -y -d boa_grammar.y
  3. #gcc -g -O2 -pipe -Wall -I. -c -o y.tab.o y.tab.c -DDEBUG
  4. gcc -g -O2 -pipe -Wall -I. -c -o y.tab.o y.tab.c
  5. flex boa_lexer.l
  6. gcc -g -O2 -pipe -Wall -I. -c -o lex.yy.o lex.yy.c
  7. gcc -g -O2 -pipe -Wall -I. -c -o config.o config.c
  8. gcc -o parse y.tab.o lex.yy.o config.o
  9. clean:
  10. 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()函数指定要解析的文件,或将文件名以函数参数的形式传入,就可以解析指定的文件名中的配置参数。
阅读(3970) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~