2010-03-31 6 views
3

다음 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, 제발.

+4

코드가 너무 많습니다. 가능한 경우 관련 부분으로 잘라내십시오. – Macke

답변

4

나는 코드로 모든 것이 훌륭하다고 믿습니다. 모든 입력이 제대로 일치하면 후행 공백 문자에서 구문 분석이 실패합니다. 이유는 parse() 함수가 건너 뛰기 후 단계를 실행하지 않기 때문입니다 (즉, 마지막 일치하는 구문 분석기 이후에 건너 뛴 구문 분석기를 호출하지 않기 때문). 이 문제를 해결하는 가장 쉬운 방법은 문법에 !end_p를 추가하는 것입니다

필요한 건너 뛰기를 강제하고 입력이 전체의 일치 된 확인합니다
parse_info<> info = parse(str.c_str(), elementary_subst >> !end_p, space_p); 

.

+0

감사합니다. 수정을했습니다 : ">>! end_p"를 문법 개체에 추가하십시오. 불행하게도 출력은 여전히 ​​동일합니다. 문법 정의 나 추가 된 함수에 여전히 문제가 있습니다. – Decmanc04

+0

태그가 없습니다. 나는 당신의 제안을 적용했고 문법의 약간의 수정으로 지금은 잘 작동하고 모든 변수가 포착됩니다. 출력의 주요 부분은 다음과 같습니다 부채 | -> LoanRequest ... 부채 | -> outstandingLoan1 ... 부채 | -> outstandingLoan1 SIMPLE 대체 PUSH (loanammount) PUSH (paidammount) SUBTRACT PUSH (newDebt = loanammount-paidammount) ... newDebt | -> loanammount ... newDebt | -> paidammount 종속성 쌍 "부채 | -> outstandingLoan1는"비록 SIMPLE 대체 중복, I 나중에 코드를 검사 할 때이를 고칠 수 있어야합니다. 다시 한번 감사드립니다. – Decmanc04

+0

안녕하세요, 저는 다시 몇 가지 문제에 부딪 혔습니다. 종속성 쌍 "부채 | -> outstandingLoan1"의 중복을 고정 후, 나는 부분적으로 포함 할 수있는 문법을 확장 machine_subst \t \t \t \t = ((simple_subst \t \t \t \t | multi_subst \t \t \t \t | 선택 \t \t \t \t | multi_choice \t \t \t \t |,617을 선택\t \t \t \t | 조건부 \t \t \t \t | 사전 조건) \t \t \t \t >> * (ch_p (';') >> machine_subst)); 및 "machine_subst"시작 기호로 사용됩니다. 그런 다음 파서는 "||" 다시. 시작 심볼을 "multi_subst"로 다시 바꿨을 때, "machine_subst"를 사용해야합니다. – Decmanc04

0

내가 machine_subst 규칙을 바꿀 때 어떤 이유로 문법이 올바르게 구문 분석되지 않았습니다 ... "machine_subst = (((simple_subst) | (multi_subst) | (choice) | (multi_choice) | (select) | (conditional) | (preconditional))". 각 하위 규칙을 괄호 안에 넣으면 옵션이 하위 규칙과 각 하위 규칙 사이에 있음을 명시합니다. 문법 정의가 왜 이런 식으로 행동하는지 어떤 생각이 들겠지 만 그것이 현재의 나에게 효과적이므로 내 현재 프로젝트에는 중요하지 않습니다. |

SUBST = multi_choice 다음과 같이

1

나는 문법을 재 설계했다, 그 문제를 해결 한 것 같다 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 = & do_mSubst (

+ (str_p ("||") >> simple_subst) simple_subst) ;

 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] 
       ; 

... ... 는 지금 f3.txt 및 f4.txt의 시작 파일 "SUBST는"f1.txt 규칙 및 f2.txt과 "표현"을 사용합니다.

start() const { return subst; // return machine_subst; // return expression; // return if_select_pre_subst; // return multi_choice; // return unbounded_choice; }

아직 문법을 작성 중이므로 추가 문제가있는 경우 게시 해 드리겠습니다.