User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cpp:http-compiler [2019-05-28 15:26]
cpp:http-compiler [2020-02-15 00:57] (current)
Line 1: Line 1:
 +=====bison/​flex based HTTP header compiler (lexer and parser)=====
 +
 +For sample. Now parse only 4 header line types. ​
 +
 +===requestcc.cpp===
 +
 +<code c++ requestcc.cpp>​
 +/*
 + *
 + * Copyright 2004-2019 Oleg Borodin ​ <​borodin@unix7.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 2 of the License, 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., 51 Franklin Street, Fifth Floor, Boston,
 + * MA 02110-1301, USA.
 + *
 + */
 +
 +#include <​iostream>​
 +#include <​sstream>​
 +
 +#include "​requestyy.hpp"​
 +#include "​requestll.hpp"​
 +#include "​requestcc.hpp"​
 +
 +namespace requestcc {
 +
 +void compiler(const std::​string&​ buffer, srv6::​request&​ request) {
 +
 +    std::​stringstream out;
 +    std::​stringstream in;
 +    in << buffer;
 +
 +    std::cerr << in.str() << std::endl;
 +    std::cerr << std::endl;
 +
 +    requestcc::​lexer l(buffer, out);
 +    requestcc::​parser parser(l, request);
 +    parser();
 +
 +
 +    //std::cerr << out.str() << std::endl;
 +    //std::cerr << std::endl;
 +}
 +
 +} // namespace requestcc
 +
 +</​code>​
 +
 +===requestcc.hpp===
 +
 +<code c++ requestcc.hpp>​
 +/*
 + *
 + * Copyright 2004-2019 Oleg Borodin ​ <​borodin@unix7.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 2 of the License, 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., 51 Franklin Street, Fifth Floor, Boston,
 + * MA 02110-1301, USA.
 + *
 + */
 +#ifndef REQUESTCC_HPP
 +#define REQUESTCC_HPP
 +
 +namespace srv6 {
 +
 +struct request {
 +    struct auth {
 +        std::string method;
 +        std::string key;
 +    };
 +
 +    std::string method;
 +    std::string uri;
 +    std::string hostname;
 +    int clen = 0;
 +    auth auth;
 +};
 +
 +} // namespace srv6
 +
 +namespace requestcc {
 +
 +void compiler(const std::​string&​ raw, srv6::​request&​ request);
 +
 +} // namespace requestcc
 +
 +#endif
 +
 +</​code>​
 +
 +===request.ll===
 +
 +<code c++ request.ll>​
 +%top{
 +#include <​memory>​
 +#include "​requestyy.hpp"​
 +%}
 +
 +%option bison-cc
 +%option bison-locations
 +%option noyywrap
 +%option reentrant
 +
 +%option namespace="​requestcc"​
 +%option lexer="​lexer"​
 +
 +%option lex="​yylex"​
 +//​%outfile="​requestll.cpp"​
 +%header-file="​requestll.hpp"​
 +%option bison-cc-namespace="​requestcc"​
 +
 +%x GET
 +%x AUTH
 +%x HOST
 +%x CLEN
 +
 +GET         ​GET|POST|HEAD
 +URI             ​\/​[\/​a-zA-Z0-9_%&?​=.]{0,​1024}
 +PROTO           ​HTTP\/​1.0|HTTP\/​1.1
 +
 +HOST            (?i:host):
 +HNAME           ​[a-zA-Z_][a-zA-Z0-9\._]{0,​512}
 +PORT            [1-6][0-9]{1,​4}
 +
 +AUTH           ​(?​i:​authorization):​
 +AMET           ​(?​i:​SAPISIDHASH|BASIC)
 +AKEY           ​[a-zA-Z_][a-zA-Z0-9_=]{1,​1024}
 +
 +CLEN            (?​i:​content\-length):​
 +CSIZE           ​[1-9][0-9]{1,​64}
 +
 +SEMIC           :
 +NL              [\t ]{0,​64}\n|[\t ]{0,64}\r\n
 +SPACE           [\t ]{1,64}
 +
 +%%
 +
 +{GET}            { start(GET); yylval.str = str(); return requestcc::​parser::​token::​GET;​ }
 +<​GET>​{SPACE} ​        { return requestcc::​parser::​token::​SPACE;​ }
 +<​GET>​{URI} ​          { yylval.str = str(); return requestcc::​parser::​token::​URI;​ }
 +<​GET>​{PROTO} ​        { return requestcc::​parser::​token::​PROTO;​ }
 +<​GET>​{NL} ​           { start(INITIAL);​ return requestcc::​parser::​token::​NL;​ }
 +
 +{HOST} ​           { start(HOST);​ return requestcc::​parser::​token::​HOST;​ }
 +<​HOST>​{HNAME} ​        { yylval.str = str(); return requestcc::​parser::​token::​HNAME;​ }
 +<​HOST>​{PORT} ​         { yylval.str = str(); return requestcc::​parser::​token::​PORT;​ }
 +<​HOST>​{SPACE} ​        { return requestcc::​parser::​token::​SPACE;​ }
 +<​HOST>​{SEMIC} ​        { return requestcc::​parser::​token::​SEMIC;​ }
 +<​HOST>​{NL} ​           { start(INITIAL);​ return requestcc::​parser::​token::​NL;​ }
 +
 +{AUTH} ​           { start(AUTH);​ return requestcc::​parser::​token::​AUTH;​ }
 +<​AUTH>​{AMET} ​        { yylval.str = str(); return requestcc::​parser::​token::​AMET;​ }
 +<​AUTH>​{AKEY} ​        { yylval.str = str(); return requestcc::​parser::​token::​AKEY;​ }
 +<​AUTH>​{SPACE} ​       { return requestcc::​parser::​token::​SPACE;​ }
 +<​AUTH>​{NL} ​          { start(INITIAL);​ return requestcc::​parser::​token::​NL;​ }
 +
 +{CLEN} ​           { start(CLEN);​ return requestcc::​parser::​token::​CLEN;​ }
 +<​CLEN>​{CSIZE} ​        { yylval.str = str(); return requestcc::​parser::​token::​CSIZE;​ }
 +<​CLEN>​{SPACE} ​        { return requestcc::​parser::​token::​SPACE;​ }
 +<​CLEN>​{NL} ​           { start(INITIAL);​ return requestcc::​parser::​token::​NL;​ }
 +
 +
 +%%
 +
 +</​code>​
 +
 +===request.yy===
 +
 +<code c++ request.yy>​
 +%skeleton "​lalr1.cc"​
 +%require ​ "​3.2"​
 +%language "​c++"​
 +
 +%define parse.trace
 +%define parse.error verbose
 +
 +%defines "​requestyy.hpp"​
 +%output "​requestyy.cpp"​
 +
 +%define api.namespace { requestcc }
 +%define api.location.file "​requestloc.hpp"​
 +%locations
 +
 +%code requires{
 +    #include <​iostream>​
 +    #include <​string>​
 +    #include <​vector>​
 +    #include <​memory>​
 +
 +    #include "​requestcc.hpp"​
 +
 +    namespace requestcc {
 +            class lexer;
 +    }
 +}
 +
 +
 +%parse-param {requestcc::​lexer&​ lex} {srv6::​request&​ req}
 +
 +
 +%code{
 +    #include "​requestll.hpp"​
 +
 +    #undef yylex
 +    #define yylex lex.yylex
 +
 +    std::string tolower(std::​string s) {
 +        std::​transform(s.begin(),​ s.end(), s.begin(), [](unsigned char c){
 +                return std::​tolower(c);​
 +        });
 +        return s;
 +    }
 +}
 +
 +%code requires {
 +    struct lexdata {
 +        std::string str;
 +    };
 +}
 +%define api.value.type {struct lexdata}
 +
 +%token <str> GET
 +%token <str> URI
 +%token PROTO
 +
 +%token HOST
 +%token <str> HNAME
 +%token <str> PORT
 +
 +%token AUTH
 +%token <str> AMET
 +%token <str> AKEY
 +
 +%token CLEN
 +%token <str> CSIZE
 +
 +%token SEMIC
 +%token SPACE
 +%token NL
 +%token END
 +
 +
 +%%
 +
 +assignments : assignment
 +            | assignment assignments
 +            ;
 +assignment ​ : some NL
 +            ;
 +
 +some        : req
 +            | host
 +            | auth
 +            | clen
 +            | error
 +            ;
 +req         : GET SPACE URI SPACE PROTO
 +                        { req.method = tolower($1);​ req.uri = $3; }
 +            ;
 +
 +host        : HOST SPACE HNAME SEMIC PORT
 +                        { req.hostname = tolower($3);​ }
 +            ;
 +
 +auth        : AUTH SPACE AMET SPACE AKEY
 +                        { req.auth.method = tolower($3);​ req.auth.key = $5; }
 +            ;
 +
 +clen        : CLEN SPACE CSIZE
 +                        {   ​std::​string clen($3);
 +                            if (clen.length() > 0) {
 +                                req.clen = std::​stoi(clen);​
 +                            } else {
 +                                req.clen = 0;
 +                            }
 +                        }
 +            ;
 +%%
 +void requestcc::​parser::​error(const location_type&​ loc, const std::​string&​ msg) {
 +    std::cerr << msg << " at " << loc << std::endl;
 +}
 +
 +</​code>​
 +
 +----
 +[<>]