boost의 spirit 질문입니다.

lacovnk의 이미지

"sql bla"가 유효한 sql query문이라고 가정하고, "sql"은 유효하지 않다고 합시다.

sql bla;sql bla;sql bla;sql [엔터]
bla;[엔터]

다음과 같이 쳤을때, 앞의 세 sql bla는 엔터를 치자 마자 처리가 되고, 마지막 것은 엔터를 친 후에 bla;를 마저 치고 엔터를 치고 난 후에 들어 올 경우 처리를 해야겠지요.

그런데, spirit에서 이를 어떻게 해야 할지 모르겠습니다 orz

들어오는 것을 buffering해서 끝의 미완성된 sql을 떼어버리고 parser에게 넘길까 하는데.. 그건 구차한 방법 같고 -o-

documentation의 어느 부분을 읽어야 할지 난감합니다;; 힌트 주세요~ :)

현재는 다음과 같이 쓰고 있습니다.

int
main()
{
        string str_in,str_buf;
        sql_grammar sqlg;

        print_prompt();
        while (getline(cin, str_in))
        {
                str_buf += str_in;
                parse_info<> info = parse(str_buf.c_str(),sqlg,space_p);
                if (false == info.full)
                {
                        cout << "Parsing failed\n";
                        cout << "stopped at: \"" << info.stop << "\"\n";
                }

                print_prompt();
        }

        cout << "Bye \n\n";
        return 0;
}
ssggkim의 이미지

Quote:

들어오는 것을 buffering해서 끝의 미완성된 sql을 떼어버리고 parser에게 넘길까 하는데.. 그건 구차한 방법 같고 -o-

전처리하는 부분을 만드시는게 좋을 것 같습니다. 추후 확장하기도 좋을 듯 싶구요.
문제는 쪼개서 푸는게 쉽다고 생각하는지라... :wink:

lacovnk의 이미지

str_buf 을 두어서, 세미콜론 기준으로 파서에게 넘겨주기로 하는 걸로 임시 처방을 했습니다.

두번째, error recovery관련입니다.

http://spirit.sourceforge.net/distrib/spirit_1_8_3/libs/spirit/doc/error_handling.html
여기에 보면

Quote:
error_status<T>
f(ScannerT const& scan, ErrorT error);

Where scan points to the scanner state prior to parsing and error is the error that arose. The handler is allowed to move the scanner position as it sees fit, possibly in an attempt to perform error correction. The handler must then return an error_status<T> object.

으로, 에러 핸들링 함수는 scanner의 포지션을 바꿀 수 있다고 되어 있습니다.

http://spirit.sourceforge.net/distrib/spirit_1_8_3/libs/spirit/doc/indepth_the_scanner.html
여기에서,

Quote:
scanner const& operator++() move the scanner forward

를 이용해서, 에러가 나면 한칸씩 앞으로 가면서 파싱을 재 시도하게 만들기 위해서, 핸들러를 다음과 같이 만들었습니다.

struct handler
{
    template <typename ScannerT, typename ErrorT>
        error_status<>
        operator()(ScannerT const& scan, ErrorT const& error) const
        {
            cout << "Syntax Error is Detected! first(" << scan.first << ") last(" << scan.last << ")" << endl;

            if(true == scan.at_end()){return error_status<>(error_status<>::fail);}
            ++scan;
            cout << "After.. first(" << scan.first << ") last(" << scan.last << ")" << endl;
            return error_status<>(error_status<>::retry);
        }
};

그런데 결론은.. "asdf"라는 명령어를 주고 찍어보면,

Quote:
Syntax Error is Detected! first(asdf;) last()
After.. first(sdf;) last()
Syntax Error is Detected! first(asdf;) last()
After.. first(sdf;) last()
Syntax Error is Detected! first(asdf;) last()
After.. first(sdf;) last()

이렇게 무한히 찍게 됩니다. 즉, 저 핸들러 함수 내에서 ++scan 한 것이 반영이 안되는 것이죠;

1. 보아하니, 핸들러 함수에서 const로 scan을 받는다 하였는데, 이게 상관이 있나요? 참조를 const로 부를 경우, 안의 내용도 바뀌지 않는 다는 것을 보장하는 것인가요? (기초질문이군요ㅠ) 그런데, 만약 불변이라면, 컴파일에서 에러를 내야 하는 것 같은데, 에러도 나지 않았습니다.

2. 분명 문서에서는 scanner의 position을 바꾼다 하였는데, 어떻게 하면 될까요?; ++scan.first 도 마찬가지의 행동을 보입니다 (어차피 operator++의 내용이 저것인지라..)

ssggkim의 이미지

lacovnk wrote:

1. 보아하니, 핸들러 함수에서 const로 scan을 받는다 하였는데, 이게 상관이 있나요? 참조를 const로 부를 경우, 안의 내용도 바뀌지 않는 다는 것을 보장하는 것인가요? (기초질문이군요ㅠ) 그런데, 만약 불변이라면, 컴파일에서 에러를 내야 하는 것 같은데, 에러도 나지 않았습니다.

error handling을 쓰지는 않지만 궁금해서 찾아보았습니다.

http://users.utu.fi/~sisasa/oasis/cppfaq/const-correctness.html#[18.7]
을 보시면 ScannerT const& scan는 곧 const ScannerT & scan이 되고 그렇다면 scan값을 바꿀 수 없을 것 같습니다.
에러가 안나는 이유는 compiler에 따라 달라질 수 있을 것 같습니다.

별로 도움이 되지 못한 답변이군요. :oops:

lacovnk의 이미지

g++이고, -Wall option을 줬는데 아주 멀쩡합니다. orz

spirit에서 scanner의 position을 바꾸는게 ++scan 말고 다른 방법이 있나요?

lacovnk의 이미지

reserved 키워드를 처리를 못하고 있습니다 -o-

Quote:
struct sql_grammar :
public grammar<sql_grammar>
{
template <typename ScannerT>
struct definition
{
definition(sql_grammar const& self)
{
keywords = "table",...;
typedef inhibit_case<strlit<> > token_t;
token_t TABLE = as_lower_d["table"];

query_select = (SELECT >> column_name_list >> FROM >> table_name >> !(where_clause) >> SEMI)[&do_select];

table_name = identifier;
identifier = nocase_d[lexeme_d[(alpha_p >> *(alnum_p | '_'))]];
}

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

// declare the keywords
symbols<> keywords;
// rule..
rule<ScannerT>
command, blabla...
};
};

이렇게 해놓고 쓰고 있는데..

select * from table

이런 코드에서 table이 TABLE로 인식이 안되고 identifier로 인식이되는지, 에러가 나지 않습니다 -o-

1. keywords는 대체 뭔가요?;; grammer를 뒤져봐도 안나오고 -o-
2. keywords를 먼지 인식하는, 해결방법은 무엇인가요?

ssggkim의 이미지

보셨을 것 같기도 한데 이걸 참조해보시면 어떨까요?

http://spirit.sourceforge.net/repository/applications/spirit_sql.zip

select 문만 구현했다고 합니다.

lacovnk의 이미지

저걸 토대로 추가하고 수정하고 있는데, 저 프로그램 역시 예약어를 키워드로 받아들이지 않는 문제가 있습니다 orz

사실 keyword 같은 것 준 것도 저 소스에서 그대로.. 8)

으음. spirit을 이용한 좀더 큰 어플을 보고 싶은데, sf에는 없네요. 으음..

사용해보신 분 계신 것 같은데 경험담이라도 부탁드려요~ :)

ssggkim의 이미지

lacovnk wrote:

select * from table

이런 코드에서 table이 TABLE로 인식이 안되고 identifier로 인식이되는지, 에러가 나지 않습니다 -o-

위 code대로라면 "table"이 identifier로 인식되는데 아무 문제가 없으니

table_name = identifier-keywords; 

식으로 해야 하지 않을까요?
compile이 될지 모르겠네요. 해보지 않고 올리는 거라 죄송합니다. :oops:

lacovnk의 이미지

키워드를 빼주니 되는군요. 감사합니다! :)

근데 여전히 에러처리는 되지 않네요. 으음..

const를 빼도 마찬가지 입니다.(루틴 내에서는 한칸 뒤로 가는데, 찍어보면 제자리에서 retry하고 있습니다) 좀더 자세히 알아봐야겠군요.

lacovnk의 이미지

identifier = (nocase_d[lexeme_d[+(alpha_p | '_')]] - keywords);
column_name = token_node_d[identifier];
column_name_list = infix_node_d[column_name >> *(COMMA >> column_name)];

이렇게, column_name_list 이하에 column_name이 주렁주렁 달리게 하고 싶습니다

그런데, column_name_list에서, column_name이 한번만 나올 경우에는 하나만 매달리는 것이 아니라 아예 올라와버립니다.

즉,

1) parent - column_name_list - column_name(a)
                      \- column_name(b)

2) parent - column_name_list - column_name(a)

3) parent - column_name(a)

1)은 잘 되는데, 2)으로 되어야 할 것이 3)으로 되어버려서, parent->children.size()이 0이 되어버립니다. 으으...

2번으로 하려면 어떻게 문법을 정의해야 할 까요?;;

그리고, 한 노드의 children을 다음과 같이 접근 했는데, 좀더 깔끔한 표현은 없을까요? parent->children이 vector로 관리된다고 하는데... 각각을 다음과 같이 접근 했습니다.

iter_t first = i->children.begin();
iter_t node_table = first;
iter_t node_column = ++first;
iter_t node_value = ++first;

그런데, iterator가 아닌, 각각의 노드를 받고 싶은데, type를 뭐로 해야 할 지 모르겠습니다 orz

tree_node node_table = i->children[0];
tree_node node_column = i->children[1];
tree_node node_value = i->children[2];    
lacovnk의 이미지

일단, AST는 불필요한 노드를 없애버리는 성질이 있었군요 -o-

http://spirit.sourceforge.net/distrib/spirit_1_8_3/libs/spirit/doc/trees.html

Quote:
When calling ast_parse, the tree gets generated differently. It mostly works the same as when generating a parse tree. The difference happens when a rule only generated one sub-node. Instead of creating a new level, ast_parse will not create a new level, it will just leave the existing node.

main 코드에서 ast_parse를 pt_parse로 바꿔주니 잘 됩니다 ㅎ (include 잡아주고..)

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.