帮助提升语法

时间:2010-03-31 13:37:57

标签: c++ boost grammar semantics action

我一直在使用以下win32控制台代码尝试使用Boost Spirit语法模板解析嵌入在C ++中的B机器语法。我是一个相对较新的Boost用户。代码编译,但是当我运行VC ++ 2008生成的.exe文件时,程序部分解析输入文件。我认为问题在于我的语法定义或附加为语义的函数。

代码如下:

// BIFAnalyser.cpp : Defines the entry point for the console application.
//
//
/*=============================================================================
    Copyright (c) Temitope Jos Onunkun 2010 
    http://www.dcs.kcl.ac.uk/pg/onun/

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
////////////////////////////////////////////////////////////////////////////
//                                                                        //
//  B Machine parser using the Boost "Grammar" and "Semantic Actions".    // 
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#include <boost/spirit/core.hpp>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <utility>

///////////////////////////////////////////////////////////////////////////////////////////
using namespace std;
using namespace boost::spirit;

///////////////////////////////////////////////////////////////////////////////////////////
//
//  Semantic actions
//
////////////////////////////////////////////////////////////////////////////
vector<string> strVect;


namespace 
{
 //semantic action function on individual lexeme
    void    do_noint(char const* str, char const* end)
    {
        string  s(str, end);

  if(atoi(str))
  {
   ;
  }
  else
  {
  strVect.push_back(s);
        cout << "PUSH(" << s << ')' << endl;
  }
    }

 //semantic action function on addition of lexemes
void do_add(char const*, char const*)    
{ 
 cout << "ADD" << endl; 
 for(vector<string>::iterator vi = strVect.begin(); vi < strVect.end(); ++vi)
   cout << *vi << " ";
}

 //semantic action function on subtraction of lexemes
void do_subt(char const*, char const*)   
{ 
 cout << "SUBTRACT" << endl; 
 for(vector<string>::iterator vi = strVect.begin(); vi < strVect.end(); ++vi)
   cout << *vi << " ";
}

 //semantic action function on multiplication of lexemes
void do_mult(char const*, char const*)   
{ 
 cout << "\nMULTIPLY" << endl; 
 for(vector<string>::iterator vi = strVect.begin(); vi < strVect.end(); ++vi)
   cout << *vi << " ";
 cout << "\n";
}

 //semantic action function on division of lexemes
void do_div(char const*, char const*)    
{ 
 cout << "\nDIVIDE" << endl; 
 for(vector<string>::iterator vi = strVect.begin(); vi < strVect.end(); ++vi)
   cout << *vi << " ";
}

 //semantic action function on simple substitution
void do_sSubst(char const* str, char const* end)    
{ 
   string  s(str, end);

  //use boost tokenizer to break down tokens
 typedef boost::tokenizer<boost::char_separator<char> > Tokenizer;
 boost::char_separator<char> sep("-+/*:=()"); // default char separator
      Tokenizer tok(s, sep);
 Tokenizer::iterator tok_iter = tok.begin();

pair<string, string > dependency; //create a pair object for dependencies

  //save first variable token in simple substitution
 dependency.first = *tok.begin();

  //create a vector object to store all tokens 
 vector<string> dx;
    // 
      for( ; tok_iter != tok.end(); ++tok_iter)  //save all tokens in vector
  {
   dx.push_back(*tok_iter );
  }

 vector<string> d_hat; //stores set of dependency pairs

 string dep; //pairs variables as string object



 for(int unsigned i=1; i < dx.size()-1; i++)
 {
        dependency.second = dx.at(i);
     dep = dependency.first + "|->" + dependency.second + " ";
   d_hat.push_back(dep);
 }


 cout << "PUSH(" << s << ')' << endl;

 for(int unsigned i=0; i < d_hat.size(); i++)
    cout <<"\n...\n" << d_hat.at(i) << " ";

 cout << "\nSIMPLE SUBSTITUTION\n";  

}

    //semantic action function on multiple substitution
void do_mSubst(char const* str, char const* end)    
{ 
  string  s(str, end);

  //use boost tokenizer to break down tokens
  typedef boost::tokenizer<boost::char_separator<char> > Tok;
  boost::char_separator<char> sep("-+/*:=()"); // default char separator
  Tok tok(s, sep);
  Tok::iterator tok_iter = tok.begin();

 // string start = *tok.begin();

  vector<string> mx;

  for( ; tok_iter != tok.end(); ++tok_iter)  //save all tokens in vector
  {
 mx.push_back(*tok_iter );
  }

 mx.push_back("END\n");  //add a marker "end" 

 for(unsigned int i=0; i<mx.size(); i++)
 {
  // if(mx.at(i) == "END" || mx.at(i) == "||" )
  //  break;
  // else if( mx.at(i) == "||")
  //   do_sSubst(str, end); 
  // else 
  // {
  //   do_sSubst(str, end); 

  // }

  cout << "\nTokens ... " << mx.at(i) << " ";
 }


  cout << "PUSH(" << s << ')' << endl;
  cout << "MULTIPLE SUBSTITUTION\n";
 } 

} 

////////////////////////////////////////////////////////////////////////////
//
//  Simple Substitution Grammar
//
////////////////////////////////////////////////////////////////////////////

//  Simple substitution grammar parser with integer values removed
struct Substitution : public grammar<Substitution>
{
    template <typename ScannerT>
    struct definition
    {
        definition(Substitution const& )
        {
  multi_subst 
       = (simple_subst [&do_mSubst]
       >> +( str_p("||") >> simple_subst [&do_mSubst])  
       )
       ;

  simple_subst 
    =  (Identifier >> str_p(":=")  
>> expression)[&do_sSubst]
         ;

  Identifier
    = alpha_p >> +alnum_p//[do_noint]
    ;

            expression
                  =   term
                     >> *(   ('+' >> term)[&do_add]
                        |   ('-' >> term)[&do_subt]
                        )
                  ;

            term
                  =   factor
                     >> *(   ('*' >> factor)[&do_mult]
                        |   ('/' >> factor)[&do_div]
                        )
                  ;

            factor
                =   lexeme_d[( (alpha_p >> +alnum_p) | +digit_p)[&do_noint]]
                |   '(' >> expression >> ')'
                |   ('+' >> factor)
                ;
        }
rule<ScannerT> expression, term, factor, Identifier, simple_subst, 
   multi_subst ;

        rule<ScannerT> const&
        start() const 
  { 
   return multi_subst; 
  }
    };
};

////////////////////////////////////////////////////////////////////////////
//
//  Main program
//
////////////////////////////////////////////////////////////////////////////
int
main()
{
    cout << "************************************************************\n\n";
    cout << "\t\t...Machine Parser...\n\n";
    cout << "************************************************************\n\n";
   // cout << "Type an expression...or [q or Q] to quit\n\n";

//prompt for file name to be input
cout << "Please enter a filename...or [q or Q] to quit:\n\n "; 
char strFilename[256]; //file name store as a string object
cin >> strFilename;

ifstream inFile(strFilename); // opens file object for reading
  //output file for truncated machine (operations only)


Substitution elementary_subst;  //  Simple substitution parser object

string str, next;
// inFile.open(strFilename);
while (inFile >> str)
  {
  getline(cin, next);

  str += next;

        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        parse_info<> info = parse(str.c_str(), elementary_subst, space_p);

        if (info.full)
        {
            cout << "\n-------------------------\n";
            cout << "Parsing succeeded\n";
            cout << "\n-------------------------\n";
        }
        else
        {
            cout << "\n-------------------------\n";
            cout << "Parsing failed\n";
            cout << "stopped at: \": " << info.stop << "\"\n";
            cout << "\n-------------------------\n";
        }
    }
    cout << "Please enter a filename...or [q or Q] to quit\n";
    cin >> strFilename;


    return 0;
}

The contents of the file I tried to parse, which I named "mf7.txt" is given below:

debt:=(LoanRequest+outstandingLoan1)*20 || newDebt := loanammount-paidammount


The output when I execute the program is:

************************************************************
                ...Machine Parser...
************************************************************
Please enter a filename...or [q or Q] to quit: 
c:\tplat\mf7.txt
PUSH(LoanRequest)
PUSH(outstandingLoan1)
ADD
LoanRequest outstandingLoan1
MULTIPLY
LoanRequest outstandingLoan1
PUSH(debt:=(LoanRequest+outstandingLoan1)*20)
...
debt|->LoanRequest
...
debt|->outstandingLoan1
SIMPLE SUBSTITUTION
Tokens ... debt
Tokens ... LoanRequest
Tokens ... outstandingLoan1
Tokens ... 20
Tokens ... END 
PUSH(debt:=(LoanRequest+outstandingLoan1)*20)
MULTIPLE SUBSTITUTION
-------------------------
Parsing failedstopped at: ": "
-------------------------

我的意图是只捕获文件中的变量,我设法做到了“||”串。显然,该程序没有解析超出“||”输入文件中的字符串。我将非常感谢帮助修复语法。请SOS。

3 个答案:

答案 0 :(得分:4)

我相信你的代码一切都很好。在所有输入都已正确匹配后,解析在尾随空格字符处失败。原因是parse()函数不执行跳过后的步骤(即它不会在最后一个匹配的解析器之后调用跳过解析器)。解决此问题的最简单方法是在语法中添加!end_p

parse_info<> info = parse(str.c_str(), elementary_subst >> !end_p, space_p); 

强制所需的跳过并确保您的输入已完全匹配。

答案 1 :(得分:1)

我重新设计了如下语法,这似乎解决了这个问题:

SUBST                     = multi_choice                     | machine_subst                     ;

        multi_choice 
                = machine_subst
                >> +( str_p("[]") >> machine_subst )
                ;


        machine_subst
                = (  multi_subst 
                | simple_subst
                | if_select_pre_subst
                | unbounded_choice )[&do_machSubst]
                ;

... ...

multi_subst                     =(simple_subst

  
    

+(str_p(“||”)&gt;&gt; simple_subst)                           )[&amp; do_mSubst]                         ;

  
        simple_subst
                = (identifier
                >> str_p(":=") >> arith_expr) [&do_sSubst]
                ;

        expression
                = predicate
                | logic_expr
                | arith_expr
                ;

        predicate
                = ( logic_expr 
                >> +( ( str_p("&") >> logic_expr )
                |     ( str_p("OR") >> logic_expr ) ) )[&do_predicate]
                ;

        logic_expr 
                = ( identifier
                >> ( (str_p("<") >> arith_expr)
                | (str_p(">")  >> arith_expr)
                | (str_p("/:")  >> arith_expr)
                | (str_p("<:")  >> arith_expr)
                | (str_p("/<:")  >> arith_expr)
                | (str_p("<<:")  >> arith_expr)
                | (str_p("/<<:")  >> arith_expr)
                | (str_p("<=")  >> arith_expr)
                | (str_p("=")  >> arith_expr)
                | (str_p(">=")  >> arith_expr)
                | (str_p("=>")  >> arith_expr) )
                )  [&do_logicExpr]
                ;

... ... 我现在对文件f1.txt和f2.txt使用启动规则“subst”,对f3.txt和f4.txt使用“expression”。

start()const         {             返回;             // return machine_subst;             //返回表达式;             //返回if_select_pre_subst;             //返回multi_choice;             //返回unbounded_choice;         }

我仍在构建语法,所以如果我有任何进一步的问题,我会发布它。

答案 2 :(得分:0)

由于某些原因我不确定,当我将machine_subst规则更改为... "machine_subst = ( ((simple_subst) | (multi_subst) | (choice) | (multi_choice) | (select) | (conditional) | (preconditional))"时,语法被正确解析。我怀疑将每个子规则放在括号中明确指定选项是在每个子规则之间而不是其中的一部分。任何想法为什么语法定义以这种方式表现都会受到赞赏,但它对我当前的项目并不重要,因为它对我有用。