Advertisement
C4Cypher

lua_grammar.cpp

Aug 4th, 2014
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.97 KB | None | 0 0
  1. //#define BOOST_SPIRIT_DEBUG
  2. #include <boost/bind.hpp>
  3. #include <boost/spirit.hpp>
  4. #include <iostream>
  5. #include "lua_parser.hpp"
  6.  
  7. /* Lua 5.0 BNF:
  8.  
  9. This BNF is extracted from http://www.lua.org/manual/5.0/manual.html#BNF
  10.  
  11. <bnf>
  12. chunk ::= {stat [';']}
  13.  
  14. block ::= chunk
  15.  
  16. stat ::=  varlist1 '=' explist1 | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | return [explist1] | break | for Name '=' exp ',' exp [',' exp] do block end | for Name {',' Name} in explist1 do block end | function funcname funcbody | local function Name funcbody | local namelist [init]
  17.  
  18. funcname ::= Name {'.' Name} [':' Name]
  19.  
  20. varlist1 ::= var {',' var}
  21.  
  22. var ::=  Name | prefixexp '[' exp ']' | prefixexp '.' Name
  23.  
  24. namelist ::= Name {',' Name}
  25.  
  26. init ::= '=' explist1
  27.  
  28. explist1 ::= {exp ','} exp
  29.  
  30. exp ::=  nil false true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp
  31.  
  32. prefixexp ::= var | functioncall | '(' exp ')'
  33.  
  34. functioncall ::=  prefixexp args | prefixexp ':' Name args
  35.  
  36. args ::=  '(' [explist1] ')' | tableconstructor | Literal
  37.  
  38. function ::= function funcbody
  39.  
  40. funcbody ::= '(' [parlist1] ')' block end
  41.  
  42. parlist1 ::=  Name {',' Name} [',' '...'] | '...'
  43.  
  44. tableconstructor ::= '{' [fieldlist] '}'
  45. fieldlist ::= field {fieldsep field} [fieldsep]
  46. field ::= '[' exp ']' '=' exp | name '=' exp | exp
  47. fieldsep ::= ',' | ';'
  48.  
  49. binop ::= '+' | '-' | '*' | '/' | '^' | '..' | '<' | '<=' | '>' | '>=' | '==' | '~=' | and | or
  50.  
  51. unop ::= '-' | not
  52. </bnf>
  53.  
  54. As one can see, there are some left recursion in this bnf: prefixexp, var, functioncall, exp.
  55. I had to add several new 'specialized' rules to avoid this.
  56.  
  57. */
  58.  
  59. namespace lua{
  60.  
  61.     ///
  62.     /// binary operator symbol table
  63.     ///
  64.     template<typename CharT>
  65.     struct binop_symbols :
  66.         boost::spirit::symbols<std::string, CharT>
  67.     {
  68.         binop_symbols()
  69.         {
  70.             add
  71.                 ("+"   , "+")
  72.                 ("-"  , "-")
  73.                 ("*"   , "*")
  74.                 ("/"    , "/")
  75.                 ("^"   , "^")
  76.                 (".."  , "..")
  77.                 ("<" , "<")
  78.                 ("<="   , "<=")
  79.                 (">"   , ">")
  80.                 (">="   , ">=")
  81.                 ("=="   , "==")
  82.                 ("~="   , "~=")
  83.                 ("and"   , "and")
  84.                 ("or"   , "or")
  85.                 ;
  86.         }
  87.  
  88.     };
  89.     const binop_symbols<char> binop_symbols_p=binop_symbols<char>();
  90.  
  91.     ///
  92.     /// unary operator symbol table
  93.     ///
  94.     template<typename CharT>
  95.     struct unop_symbols : boost::spirit::symbols<std::string, CharT>
  96.     {
  97.         unop_symbols()
  98.         {
  99.             add
  100.                 ("-"   , "-")
  101.                 ("not"  , "not")
  102.                 ;
  103.         }
  104.  
  105.     };
  106.     const unop_symbols<char> unop_symbols_p=unop_symbols<char>();
  107.  
  108.     ///
  109.     /// boolean symbols
  110.     ///
  111.     template<typename CharT>
  112.     struct boolean_symbols : boost::spirit::symbols<std::string, CharT>
  113.     {
  114.         boolean_symbols()
  115.         {
  116.             add
  117.                 ("nil"   , "nil")
  118.                 ("false"  , "false")
  119.                 ("true"  , "true")
  120.                 ;
  121.         }
  122.  
  123.     };
  124.     const boolean_symbols<char> boolean_symbols_p=boolean_symbols<char>();
  125.  
  126.     ///
  127.     /// literal grammar
  128.     ///
  129.     struct literal_grammar : boost::spirit::grammar< literal_grammar >
  130.     {
  131.         template <typename ScannerT>
  132.         struct definition
  133.         {
  134.             boost::spirit::rule<ScannerT>  
  135.                 escaped_literal,
  136.                 literal_double_bracket,
  137.                 literal_apos,
  138.                 literal_quot,
  139.                 literal;
  140.  
  141.             definition(literal_grammar const& self_)  
  142.             {
  143.                 using namespace boost::spirit;
  144.  
  145.                 escaped_literal =
  146.                     ch_p('\\') >> chset_p("abfnrtv\\\"\'[]")
  147.                     | anychar_p
  148.                     ;
  149.                 literal_double_bracket = comment_p("[[","]]");
  150.                 literal_apos = confix_p('\'', *escaped_literal, '\'');
  151.                 literal_quot = confix_p('\"', *escaped_literal, '\"');
  152.                 literal =
  153.                     literal_double_bracket
  154.                     | literal_apos
  155.                     | literal_quot
  156.                     ;
  157.  
  158.                 BOOST_SPIRIT_DEBUG_NODE(escaped_literal);
  159.                 BOOST_SPIRIT_DEBUG_NODE(literal_double_bracket);
  160.                 BOOST_SPIRIT_DEBUG_NODE(literal_apos);
  161.                 BOOST_SPIRIT_DEBUG_NODE(literal_quot);
  162.                 BOOST_SPIRIT_DEBUG_NODE(literal);
  163.             };
  164.  
  165.             boost::spirit::rule<ScannerT> const& start() const { return literal; }
  166.         };
  167.     };
  168.     const literal_grammar literal_grammar_p = literal_grammar();
  169.  
  170.     ///
  171.     /// name grammar
  172.     ///
  173.     struct name_grammar : boost::spirit::grammar< name_grammar >
  174.     {
  175.         template <typename ScannerT>
  176.         struct definition
  177.         {
  178.             boost::spirit::rule<ScannerT>  
  179.                 name;
  180.  
  181.             definition(name_grammar const& self_)  
  182.             {
  183.                 using namespace boost::spirit;
  184.  
  185.                 name = lexeme_d[ alpha_p >> *(alnum_p | ch_p('_') ) ];
  186.  
  187.                 BOOST_SPIRIT_DEBUG_NODE(name);
  188.             };
  189.  
  190.             boost::spirit::rule<ScannerT> const& start() const { return name; }
  191.         };
  192.     };
  193.     const name_grammar name_grammar_p=name_grammar();
  194.  
  195.     ///
  196.     /// the lua grammar
  197.     ///
  198.     class lua_grammar :
  199.         public boost::spirit::grammar< lua_grammar >
  200.     {
  201.     public:
  202.  
  203.         template <typename ScannerT>
  204.         struct definition
  205.         {
  206.             definition(lua_grammar const& self_)  
  207.             {
  208.                 using namespace boost::spirit;
  209.  
  210.                 Name = name_grammar_p;
  211.                 Literal = literal_grammar_p;
  212.  
  213.  
  214.                 comment = comment_p("--");
  215.                 fieldsep = chset_p(",;");
  216.                 field =
  217.                     (
  218.                         (
  219.                             confix_p(ch_p('['), exp, ch_p(']'))
  220.                             >> ch_p('=')
  221.                             >> exp
  222.                         )
  223.                         | (Name >> ch_p('=') >> exp )
  224.                         | exp
  225.                     );
  226.                 fieldlist =
  227.                     (
  228.                         list_p(field,fieldsep)>>!fieldsep
  229.                     );
  230.                 tableconstructor =
  231.                     (
  232.                         (ch_p('{') >> ch_p('}'))
  233.                         | confix_p(ch_p('{'), fieldlist, ch_p('}'))
  234.                     );
  235.  
  236.                 funcname =
  237.                     list_p( Name, ch_p('.') )
  238.                     >> !(
  239.                       ch_p(':')
  240.                       >> Name
  241.                       );
  242.                 parlist1 =  
  243.                     list_p( Name, ch_p(','))
  244.                     >> ! (
  245.                     ( ch_p(',') >> str_p("...") )
  246.                     | str_p("...")
  247.                     );
  248.                 funcbody=
  249.                     ( confix_p( ch_p('('),  !parlist1, ch_p(')') )
  250.                       >> block
  251.                       >> str_p("end")
  252.                     );
  253.                 function=
  254.                     (
  255.                         str_p("function") >> funcbody
  256.                     );
  257.                 args =
  258.                     (
  259.                         ch_p('(') >> ch_p(')')
  260.                       | confix_p( ch_p('(') , explist1, ch_p(')') )
  261.                       | tableconstructor
  262.                       | Literal
  263.                     );
  264.  
  265.                 functioncallexp =  
  266.                     args
  267.                     | ( ch_p(':') >> Name >> args );
  268.  
  269.                 functioncall =  
  270.                     (
  271.                         prefixexp_func >> functioncallexp
  272.                     );
  273.  
  274.                 varexp =  
  275.                     confix_p(ch_p('['), exp, ch_p(']'))
  276.                     | ch_p('.') >> Name;
  277.  
  278.                 var =  
  279.                     (
  280.                         Name
  281.                         | (prefixexp_var >> varexp)
  282.                     );
  283.  
  284.                 prefixexp_func =
  285.                     Name
  286.                     >>
  287.                     *(  !functioncallexp >>
  288.                     (
  289.                     varexp  
  290.                     | confix_p( ch_p('('), exp, ch_p(')') )
  291.                     )
  292.                     )
  293.                     ;
  294.  
  295.                 prefixexp_var =
  296.                     Name
  297.                     >>
  298.                     *(  ! varexp >>
  299.                     (
  300.                     functioncallexp  
  301.                     | confix_p( ch_p('('), exp, ch_p(')') )
  302.                     )
  303.                     )
  304.                     ;
  305.  
  306.                 prefixexp =
  307.                     Name
  308.                     >>
  309.                     *(  varexp
  310.                     | functioncallexp
  311.                     | confix_p( ch_p('('), exp, ch_p(')') )
  312.                     )
  313.                     ;
  314.  
  315.                 varlist1 =
  316.                     (
  317.                         list_p( var, ch_p(','))
  318.                     );
  319.  
  320.                 do_loop =
  321.                     (
  322.                         str_p("do") >> block >> str_p("end")
  323.                     );
  324.                 while_loop =
  325.                     (
  326.                         str_p("while") >> exp >> str_p("do") >> block >> str_p("end")
  327.                     );
  328.  
  329.                 repeat_loop =
  330.                     (  
  331.                         str_p("repeat") >> block  >> str_p("until") >> exp
  332.                     );
  333.                 if_loop =
  334.                     (
  335.                         str_p("if") >> exp >> str_p("then") >> block
  336.                         >> *( str_p("elseif") >> exp >> str_p("then") >> block)
  337.                         >> !(str_p("else") >> block)
  338.                         >> str_p("end")
  339.                     );
  340.                 return_ =
  341.                     (
  342.                         str_p("return") >> !explist1
  343.                     );
  344.  
  345.                 for_loop=
  346.                     (
  347.                         str_p("for") >> Name >> ch_p('=') >> exp  
  348.                         >> ch_p(',') >> exp
  349.                         >> !( ch_p(',') >> exp )
  350.                         >> str_p("do") >> block  >> str_p("end")
  351.                     );
  352.                    
  353.                 for_loop_in=
  354.                     (
  355.                         str_p("for") >> list_p( Name, ch_p(','))
  356.                         >> str_p("in") >> explist1  
  357.                         >> str_p("do") >> block >> str_p("end")
  358.                     );
  359.  
  360.                 local_function =
  361.                     (
  362.                         str_p("local") >> str_p("function") >> Name >> funcbody
  363.                     );
  364.  
  365.                 local_namelist =
  366.                     (
  367.                         str_p("local") >> namelist >> !init
  368.                     );
  369.  
  370.                 function_full =
  371.                     (
  372.                         str_p("function") >> funcname >> funcbody
  373.                     );
  374.  
  375.                 namelist =
  376.                     (
  377.                         list_p( Name, ch_p(','))
  378.                     );
  379.  
  380.                 explist1 =
  381.                     (
  382.                         exp
  383.                         >> !(
  384.                             ch_p(',')
  385.                             >> list_p(exp, ',')
  386.                             )
  387.                     );
  388.  
  389.                 init = ch_p('=') >> explist1;
  390.  
  391.                 stat =  
  392.                     (
  393.                       (varlist1 >> ch_p('=') >> explist1)
  394.                     | functioncall
  395.                     | do_loop
  396.                     | while_loop
  397.                     | repeat_loop
  398.                     | if_loop
  399.                     | return_
  400.                     | str_p("break")
  401.                     | for_loop
  402.                     | for_loop_in
  403.                     | function_full
  404.                     | local_function
  405.                     | local_namelist
  406.                     | comment
  407.                     );
  408.                     ;
  409.  
  410.                 chunk=
  411.                     (
  412.                         *( stat >> !ch_p(';') )
  413.                     );
  414.  
  415.                 block=
  416.                     (
  417.                         chunk
  418.                     );
  419.  
  420.                 exp_inner=
  421.                     boolean
  422.                     | real_p
  423.                     | Literal
  424.                     | function
  425.                     | tableconstructor
  426.                     | (unop >> exp)
  427.                     | prefixexp;
  428.  
  429.                 exp =
  430.                     (
  431.                         exp_inner >> *( binop >> exp )
  432.                         | unop >> exp
  433.                     );
  434.  
  435.                 BOOST_SPIRIT_DEBUG_NODE(binop);
  436.                 BOOST_SPIRIT_DEBUG_NODE(unop);
  437.                 BOOST_SPIRIT_DEBUG_NODE(boolean);
  438.                 BOOST_SPIRIT_DEBUG_NODE(chunk);
  439.                 BOOST_SPIRIT_DEBUG_NODE(block);
  440.                 BOOST_SPIRIT_DEBUG_NODE(stat);
  441.                 BOOST_SPIRIT_DEBUG_NODE(funcname);
  442.                 BOOST_SPIRIT_DEBUG_NODE(varlist1);
  443.                 BOOST_SPIRIT_DEBUG_NODE(var);
  444.                 BOOST_SPIRIT_DEBUG_NODE(varexp);
  445.                 BOOST_SPIRIT_DEBUG_NODE(namelist);
  446.                 BOOST_SPIRIT_DEBUG_NODE(init);
  447.                 BOOST_SPIRIT_DEBUG_NODE(explist1);
  448.                 BOOST_SPIRIT_DEBUG_NODE(exp);
  449.                 BOOST_SPIRIT_DEBUG_NODE(exp_inner);
  450.                 BOOST_SPIRIT_DEBUG_NODE(prefixexp);
  451.                 BOOST_SPIRIT_DEBUG_NODE(prefixexp_func);
  452.                 BOOST_SPIRIT_DEBUG_NODE(prefixexp_var);
  453.                 BOOST_SPIRIT_DEBUG_NODE(functioncall);
  454.                 BOOST_SPIRIT_DEBUG_NODE(functioncallexp);
  455.                 BOOST_SPIRIT_DEBUG_NODE(args);
  456.                 BOOST_SPIRIT_DEBUG_NODE(function);
  457.                 BOOST_SPIRIT_DEBUG_NODE(funcbody);
  458.                 BOOST_SPIRIT_DEBUG_NODE(parlist1);
  459.                 BOOST_SPIRIT_DEBUG_NODE(tableconstructor);
  460.                 BOOST_SPIRIT_DEBUG_NODE(fieldlist);
  461.                 BOOST_SPIRIT_DEBUG_NODE(field);
  462.                 BOOST_SPIRIT_DEBUG_NODE(fieldsep);
  463.                 BOOST_SPIRIT_DEBUG_NODE(do_loop);
  464.                 BOOST_SPIRIT_DEBUG_NODE(while_loop);
  465.                 BOOST_SPIRIT_DEBUG_NODE(repeat_loop);
  466.                 BOOST_SPIRIT_DEBUG_NODE(if_loop);
  467.                 BOOST_SPIRIT_DEBUG_NODE(return_);
  468.                 BOOST_SPIRIT_DEBUG_NODE(for_loop);
  469.                 BOOST_SPIRIT_DEBUG_NODE(for_loop_in);
  470.                 BOOST_SPIRIT_DEBUG_NODE(local_function);
  471.                 BOOST_SPIRIT_DEBUG_NODE(local_namelist);
  472.                 BOOST_SPIRIT_DEBUG_NODE(function_full);
  473.                 BOOST_SPIRIT_DEBUG_NODE(comment);
  474.                 BOOST_SPIRIT_DEBUG_NODE(Name);
  475.                 BOOST_SPIRIT_DEBUG_NODE(real_p);
  476.                 BOOST_SPIRIT_DEBUG_NODE(Literal);
  477.             };
  478.             boost::spirit::rule<ScannerT> const& start() const { return chunk; }
  479.  
  480.             binop_symbols<char> binop;
  481.             unop_symbols<char> unop;
  482.             boolean_symbols<char> boolean;
  483.  
  484.             boost::spirit::rule<ScannerT>  
  485.                 Name,
  486.                 Literal,
  487.                 chunk,
  488.                 block,
  489.                 stat,
  490.                 funcname,
  491.                 varlist1,
  492.                 prefvar,
  493.                 var,
  494.                 varexp,
  495.                 namelist,
  496.                 init,
  497.                 explist1,
  498.                 exp_inner,
  499.                 exp,
  500.                 prefixexp,
  501.                 prefixexp_func,
  502.                 prefixexp_var,
  503.                 functioncall,
  504.                 functioncallexp,
  505.                 args,
  506.                 function,
  507.                 funcbody,
  508.                 parlist1,
  509.                 tableconstructor,
  510.                 fieldlist,
  511.                 field,
  512.                 fieldsep,
  513.                 do_loop,
  514.                 while_loop,
  515.                 repeat_loop,
  516.                 if_loop,
  517.                 return_,
  518.                 for_loop,
  519.                 for_loop_in,
  520.                 local_function,
  521.                 local_namelist,
  522.                 function_full,
  523.                 comment
  524.                 ;
  525.         };
  526.  
  527.     };     
  528.  
  529.  
  530.     ///
  531.     /// a small test function...
  532.     /// returns a "home made" parse_info to avoid including spirit headers
  533.     my_parse_info test_lua_grammar(std::string const& file_name_)
  534.     {
  535.         using namespace boost::spirit;
  536.  
  537.         file_iterator<> first(file_name_.c_str());
  538.  
  539.         if (!first)
  540.             throw std::exception("could not open file");
  541.  
  542.         file_iterator<> last = first.make_end();
  543.  
  544.         typedef char                    char_t;
  545.         typedef file_iterator <char_t>  iterator_t;
  546.  
  547.         lua_grammar lua_rule;
  548.  
  549.         parse_info<iterator_t> info = parse(first, last, lua_rule, space_p);
  550.  
  551.         my_parse_info pi;
  552.         pi.hit = info.hit;
  553.         pi.full = info.full;
  554.         pi.length = info.length;
  555.  
  556.         return pi;
  557.     };
  558.  
  559. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement