Rodrigo Strauss :: Blog
Fontes do MidlParser
A função que dá início à interpretação do arquivo é a MidlParser::ParseMidlFile
CodeEntities.h
#pragma once struct IdlAttribute { IdlAttribute(const std::string& name, const std::string& value) : Name(name), Value(value) {} IdlAttribute(const std::string& name) : Name(name){} std::string Name; std::string Value; }; struct IdlParameter { IdlParameter(const std::string& type, const std::string& name) : Type(type), Name(name), IndirectionLevel(0) {} IdlParameter() : IndirectionLevel(0) {} typedef std::vector<IdlAttribute> AttributesContainer; typedef AttributesContainer::iterator AttributesIterator; typedef AttributesContainer::const_iterator ConstAttributesIterator; AttributesContainer Attributes; std::string Type; std::string Name; unsigned int IndirectionLevel; }; struct IdlMethod { IdlMethod(const std::string& name, const std::string& returnType) : Name(name), ReturnType(returnType) {} IdlMethod() {} typedef std::vector<IdlAttribute> AttributesContainer; typedef AttributesContainer::iterator AttributesIterator; typedef AttributesContainer::const_iterator ConstAttributesIterator; typedef std::vector<IdlParameter> ParametersContainer; typedef ParametersContainer::iterator ParametersIterator; typedef ParametersContainer::const_iterator ConstParametersIterator; AttributesContainer Attributes; std::string ReturnType; std::string Name; ParametersContainer Parameters; }; struct IdlInterface { IdlInterface(const std::string& name) : Name(name) {} IdlInterface() {} typedef std::vector<IdlAttribute> AttributesContainer; typedef AttributesContainer::iterator AttributesIterator; typedef AttributesContainer::const_iterator ConstAttributesIterator; typedef std::vector<IdlMethod> MethodsContainer; typedef MethodsContainer::iterator MethodsIterator; typedef MethodsContainer::const_iterator ConstMethodsIterator; AttributesContainer Attributes; std::string Name; std::string InheritsFrom; MethodsContainer Methods; }; // // functor // class IdlAttributeFindByName { private: std::string m_strName; // // Deve ser um shared_ptr pq um functor STL é passado como valor, e não como referência. // Se eu usar auto_ptr, na primeira cópia o ownership do ponteiro vao para a cópia e // ficamos sem nada... // boost::shared_ptr<std::vector<std::string> > m_MoreAttributesToFind; public: IdlAttributeFindByName(const std::string& name) : m_strName(name) {} IdlAttributeFindByName() {} void AddAttributeToFind(const std::string& str) { if(m_MoreAttributesToFind.get() == NULL) m_MoreAttributesToFind = boost::shared_ptr<std::vector<std::string> >(new std::vector<std::string>()); m_MoreAttributesToFind->push_back(str); } bool operator()(const IdlAttribute& att) { if(m_MoreAttributesToFind.get() == NULL) return att.Name == m_strName; else { return att.Name == m_strName || std::find(m_MoreAttributesToFind->begin(), m_MoreAttributesToFind->end(), att.Name) != m_MoreAttributesToFind->end(); } } };
MidlParser.h
#pragma once // // MidlParser // // Faz o parser de um arquivo IDL // class MidlParser { public: class ParseException : public std::exception { private: unsigned int m_line; string m_fileName; public: ParseException(const string& what, MidlParser& parser, const string& fileName) : std::exception(what.c_str()), m_line(parser.GetCurrentLine()), m_fileName(fileName) { } void set_line(unsigned int line) { m_line = line; } unsigned int get_line() const { return m_line; } void set_fileName(const string& fileName) { m_fileName = fileName; } const string& get_fileName() const { return m_fileName; } }; private: bool m_bParseAsImportFile; string m_parsedFileName; typedef tokenizer<char_separator<char> > TokenizerMidl; vector<string> m_KnownInterfaces; vector<string> m_KnownTypes; map<string, IdlInterface> m_ParsedInterfaces; vector<string> m_IncludePaths; vector<string> m_ParsedIncludeFiles; TokenizerMidl m_Tokenizer; TokenizerMidl::iterator m_TokenIterator; std::string m_strInvalidToken; TokenizerMidl::iterator m_LineCountIterator; mutable unsigned int m_uiCurrentLine; #ifdef _DEBUG // // isso facilita a visualização em debug // std::string m_strCurrentToken; const char* m_szCurrentToken; unsigned int m_uiBreakOnLine; #endif void Log(const string& msg); // // verifica se é um identificador válido // const string& Identifier(const string& token); const string& NextTokenAsIdentifier(); const string& CurrentTokenAsIdentifier(); void CheckIsExpectedToken(const string& str, const string& checked, const char* expected_name = NULL); void CheckExpectedNextToken(const std::string expected, const char* expected_name = NULL); void CheckExpectedCurrentToken(const std::string expected, const char* expected_name = NULL); void CheckNotExpectedToken(const string& str, const string& checked, const char* not_expected_name = NULL); void CheckNotExpectedNextToken(const std::string not_expected, const char* not_expected_name = NULL); void CheckNotExpectedCurrentToken(const std::string not_expected, const char* not_expected_name = NULL); void CheckType(const string& str, unsigned int indirectionLevel, bool mustBeInterface = false); const string& NextTokenAsType(unsigned int indirectionLevel = 0, bool mustBeInterface = false); const string& CurrentTokenAsType(unsigned int indirectionLevel = 0, bool mustBeInterface = false); void AddParsedInterface(const IdlInterface& iface); void AddKnownInterfaceName(const string& interfaceName); unsigned int GetCurrentLine(); const std::string& NextToken(bool checkEndOfFile = true, bool skipComments = true); const std::string& CurrentToken(bool checkEndOfFile = true, bool skipComments = true); void SkipUntilToken(const string& token); void SkipQuote(); void SkipUntilClose(const string& open_token, const string& close_token); void LoadKnownInterfaces(); void LoadKnownTypes(); void ParseMethod(IdlMethod* method); void ParseInterface(IdlInterface* iface); void ParseAttributes(vector<IdlAttribute>* attributes); void ParseImportFile(const string& fileName); bool IsEndOfFile(); bool OpenIncludeFile(const string& fileName, fstream* f, string* fileNameWithPath); public: MidlParser(); void AddFindPath(const string& path); void ParseMidlFile(const char* fileName); const std::map<string, IdlInterface>& GetParsedInterfaces() const; const std::vector<string>& GetKnownInterfaces() const; void Dump(ostream& s) const; private: void AddKnownType(const string& t); };
MidlParser.cpp
#pragma once #include "stdafx.h" #include "CodeEntities.h" #include "MidlParser.h" // // verifica se é um identificador válido // const string& MidlParser::Identifier(const string& token) { bool isValid = true; if(token.size() == 0 || (!std::isalpha(token[0]) && token[0] != '_')) isValid = false; else { for(string::const_iterator i = token.begin() ; i != token.end() ; ++i) { char c = *i; if(!std::isalpha(c) && !std::isalnum(c) && c != '_') { isValid = false; break; } } } if(!isValid) throw ParseException("invalid identifier: "" + token + """, *this, m_parsedFileName); return token; } const string& MidlParser::NextTokenAsIdentifier() { return Identifier(NextToken()); } const string& MidlParser::CurrentTokenAsIdentifier() { return Identifier(CurrentToken()); } void MidlParser::CheckIsExpectedToken(const string& str, const string& checked, const char* expected_name) { if(str != checked) { string ex("expected: "); if(expected_name) ex += expected_name; else { ex += """; ex += checked; ex += """; } throw ParseException(ex, *this, m_parsedFileName); } } void MidlParser::CheckExpectedNextToken(const std::string expected, const char* expected_name) { CheckIsExpectedToken(NextToken(), expected, expected_name); } void MidlParser::CheckExpectedCurrentToken(const std::string expected, const char* expected_name) { CheckIsExpectedToken(CurrentToken(), expected, expected_name); } void MidlParser::CheckNotExpectedToken(const string& str, const string& checked, const char* not_expected_name) { if(str == checked) { string ex("not expected: "); if(not_expected_name) ex += not_expected_name; else { ex += """; ex += checked; ex += """; } throw ParseException(ex, *this, m_parsedFileName); } } void MidlParser::CheckNotExpectedNextToken(const std::string not_expected, const char* not_expected_name) { CheckNotExpectedToken(NextToken(), not_expected, not_expected_name); } void MidlParser::CheckNotExpectedCurrentToken(const std::string not_expected, const char* not_expected_name ) { CheckNotExpectedToken(CurrentToken(), not_expected, not_expected_name); } void MidlParser::CheckType(const string& str, unsigned int indirectionLevel, bool mustBeInterface ) { if(std::find(m_KnownInterfaces.begin(), m_KnownInterfaces.end(), str) == m_KnownInterfaces.end()) { if(mustBeInterface == true) throw ParseException("Unknwon Type: "" + str + """, *this, m_parsedFileName); } else return; if(std::find(m_KnownTypes.begin(), m_KnownTypes.end(), str) == m_KnownTypes.end()) throw ParseException("Unknwon Type: "" + str + """, *this, m_parsedFileName); } const string& MidlParser::NextTokenAsType(unsigned int indirectionLevel, bool mustBeInterface) { CheckType(NextToken(), indirectionLevel, mustBeInterface); return CurrentToken(); } const string& MidlParser::CurrentTokenAsType(unsigned int indirectionLevel, bool mustBeInterface) { CheckType(CurrentToken(), indirectionLevel, mustBeInterface); return CurrentToken(); } void MidlParser::AddKnownInterfaceName(const string& interfaceName) { if(std::find(m_KnownInterfaces.begin(), m_KnownInterfaces.end(), interfaceName) == m_KnownInterfaces.end()) m_KnownInterfaces.push_back(interfaceName); } void MidlParser::AddParsedInterface(const IdlInterface& iface) { m_ParsedInterfaces.insert(make_pair<string, IdlInterface>(iface.Name, iface)); m_KnownInterfaces.push_back(iface.Name); AddKnownType(iface.Name); } unsigned int MidlParser::GetCurrentLine() { for( ; m_LineCountIterator != m_TokenIterator ; ++m_LineCountIterator) if(*m_LineCountIterator == "n") m_uiCurrentLine++; return m_uiCurrentLine; } const std::string& MidlParser::NextToken(bool checkEndOfFile, bool skipComments) { ++m_TokenIterator; return CurrentToken(checkEndOfFile, skipComments); } const std::string& MidlParser::CurrentToken(bool checkEndOfFile, bool skipComments) { if(IsEndOfFile()) { if(checkEndOfFile) throw ParseException("unexpected end of file", *this, m_parsedFileName); else return m_strInvalidToken; } if(skipComments) { for(;;) { if(*m_TokenIterator != "/" && *m_TokenIterator != "n") break; // // pula os comentários // while(*m_TokenIterator == "/") { TokenizerMidl::iterator next = m_TokenIterator; next++; if(*next == "/") { while(m_TokenIterator != m_Tokenizer.end() && *++m_TokenIterator != "n"); break; } else if(*next == "*") { ++m_TokenIterator; for(;;) { ++m_TokenIterator; if(IsEndOfFile()) { if(checkEndOfFile) throw ParseException("unexpected end of file", *this, m_parsedFileName); else return m_strInvalidToken; } const string& token = *m_TokenIterator; if(token == "*") { ++m_TokenIterator; if(IsEndOfFile()) { if(checkEndOfFile) throw ParseException("unexpected end of file", *this, m_parsedFileName); else return m_strInvalidToken; } if(*m_TokenIterator == "/") { ++m_TokenIterator; break; } } } } else break; } // // pula os n // while(++m_TokenIterator != m_Tokenizer.end() && *m_TokenIterator == "n"); if(IsEndOfFile()) { if(checkEndOfFile) throw ParseException("unexpected end of file", *this, m_parsedFileName); else return m_strInvalidToken; } } } #ifdef _DEBUG // // isso facilita a visualização em debug // m_strCurrentToken = *m_TokenIterator; m_szCurrentToken = m_strCurrentToken.c_str(); if(GetCurrentLine() >= m_uiBreakOnLine) { m_uiBreakOnLine = 0xFFFFFFFF; __asm int 3; } #endif return *m_TokenIterator; } void MidlParser::SkipUntilToken(const string& token) { std::find(m_TokenIterator, m_Tokenizer.end(), token); } void MidlParser::SkipQuote() { bool stringOpened = false; for(;;) { const string& token = NextToken(true, false); if(token == """) { if(stringOpened) return; else { stringOpened = true; continue; } } // // pular escape de aspa // if(token == "" && NextToken(true, false) == """) NextToken(true, false); } } void MidlParser::SkipUntilClose(const string& open_token, const string& close_token) { unsigned int deep = 0; for(;;) { if(CurrentToken() == open_token) { deep++; } else if(CurrentToken() == close_token) { deep--; if(deep == 0) break; } NextToken(); } } void MidlParser::ParseMethod(IdlMethod* method) { if(CurrentToken() == "[") ParseAttributes(&method->Attributes); method->ReturnType = CurrentTokenAsIdentifier(); method->Name = NextTokenAsIdentifier(); CheckExpectedNextToken("("); if(NextToken() != ")") { for(unsigned int uiCurrentParameter = 0 ; ; ++uiCurrentParameter) { IdlParameter param; // // vamos ver se é atributos // if(CurrentToken() == "[") { ParseAttributes(¶m.Attributes); } param.Type = CurrentTokenAsIdentifier(); while(NextToken() == "*") param.IndirectionLevel++; // // tratar sintaxe Metodo(void); // if(param.Type == "void" && CurrentToken() == ")") { break; } CheckType(param.Type, param.IndirectionLevel); param.Name = CurrentTokenAsIdentifier(); method->Parameters.push_back(param); if(NextToken() == ")") { break; } if(CurrentToken() == ",") { NextToken(); continue; } throw ParseException("expected: "," or ")"", *this, m_parsedFileName); } } NextToken(); CheckExpectedCurrentToken(";"); NextToken(); } void MidlParser::ParseInterface(IdlInterface* iface) { assert(CurrentToken() == "interface"); iface->Name = NextTokenAsIdentifier(); // // herança de interface // if(NextToken() == ":") { CheckNotExpectedNextToken("{", "interface name"); iface->InheritsFrom = CurrentTokenAsType(); CheckType(iface->InheritsFrom, 0, true); NextToken(); } CheckExpectedCurrentToken("{"); NextToken(); // // temos que colocar a própria interface na lista de tipos // conhecidos, já que um método pode receber um ponteiro // do próprio tipo // AddKnownType(iface->Name); // // métodos // if(CurrentToken() != "}") { for(;;) { IdlMethod method; ParseMethod(&method); iface->Methods.push_back(method); // // fim da interface // if(CurrentToken() == "}") break; } } CheckExpectedNextToken(";"); NextToken(); } void MidlParser::LoadKnownInterfaces() { // // essa maravilha de sintaxe é graças ao boost::assign // m_KnownInterfaces.clear(); m_KnownInterfaces += "IUnknown", "IDispatch"; return; } void MidlParser::LoadKnownTypes() { // // por enquanto vou colocar os defines tb, para facilitar. Quando // isso tiver um pré-processador isso deve ser tirado // m_KnownTypes.clear(); m_KnownTypes += "BSTR", "VARIANT", "DWORD", "LONG", "ULONG", "GUID", "REFGUID", "HRESULT", "BOOL", "LPVOID", "REFCLSID", "WCHAR", "REFIID", "VOID", "void", "VARIANT_BOOL", "USHORT", "int", "short", "UCHAR"; } void MidlParser::ParseAttributes(vector<IdlAttribute>* attributes) { std::stringstream buffer; assert(CurrentToken() == "["); for(;;) { if(CurrentToken() == "]") break; IdlAttribute att(NextTokenAsIdentifier()); // // se for vírgula, acabou esse // if(NextToken() == ",") { attributes->push_back(att); continue; } // // se abre parenteses, tem valor // if(CurrentToken() == "(") { if(NextToken() == ")") throw ParseException((boost::format("Attribute %1% has null value") % CurrentToken()).str(), *this, m_parsedFileName); // // vamos encontrar o fim do parênteses // buffer.clear(); while(CurrentToken() != ")") { buffer << CurrentToken(); NextToken(); } NextToken(); att.Value = buffer.str(); } attributes->push_back(att); } NextToken(); } void MidlParser::Log(const string& msg) { cerr << msg << endl; } bool MidlParser::IsEndOfFile() { return m_TokenIterator == m_Tokenizer.end(); } bool MidlParser::OpenIncludeFile(const string& fileName, fstream* f, string* fileNameWithPath) { for(vector<string>::const_iterator i = m_IncludePaths.begin() ; i != m_IncludePaths.end() ; ++i) { string str; f->close(); f->clear(); str = *i + fileName; f->open(str.c_str(), ios::in); if(f->good()) { if(fileNameWithPath) *fileNameWithPath = str; return true; } } return true; } void MidlParser::ParseImportFile(const string& fileName) { fstream f; string str; // // deve ter extensão IDL e não ter sido interpretado ainda // if(fileName.length() < 5 || fileName.substr(fileName.size() - 4, 4) != ".idl" || std::find(m_ParsedIncludeFiles.begin(), m_ParsedIncludeFiles.end(), fileName) != m_ParsedIncludeFiles.end()) return; MidlParser ImportParser; ImportParser.m_bParseAsImportFile = true; ImportParser.m_KnownTypes = m_KnownTypes; ImportParser.m_KnownInterfaces = m_KnownInterfaces; ImportParser.m_ParsedIncludeFiles = m_ParsedIncludeFiles; ImportParser.ParseMidlFile(fileName.c_str()); m_KnownTypes = ImportParser.m_KnownTypes; m_KnownInterfaces = ImportParser.m_KnownInterfaces; m_ParsedIncludeFiles = ImportParser.m_ParsedIncludeFiles; } // // // PUBLIC // // MidlParser::MidlParser() : m_Tokenizer(std::string()), m_bParseAsImportFile(false) { #ifdef _DEBUG m_uiBreakOnLine = 0xFFFFFFFF; #endif AddFindPath("C:Program FilesMicrosoft SDKinclude"); } void MidlParser::ParseMidlFile(const char* fileName) { fstream f; string str; std::vector<IdlAttribute> attributes; if(m_bParseAsImportFile) { if(!OpenIncludeFile(fileName, &f, &m_parsedFileName)) throw ParseException(string("error opening import file "") + fileName + """, *this, m_parsedFileName); getline(f, str, f.widen(EOF)); m_Tokenizer.assign(str,char_separator<char>("\t\r " , "\n\"*,;:{}/[]()")); m_ParsedIncludeFiles.push_back(fileName); Log(string("Parsing import file ") + fileName); } else { f.open(fileName, ios::in); if(f.fail()) throw ParseException(string("error opening file "") + fileName + """, *this, m_parsedFileName); getline(f, str, f.widen(EOF)); m_Tokenizer.assign(str,char_separator<char>("\t\r " , "\n\"*,;:{}/[]()")); m_parsedFileName = fileName; LoadKnownInterfaces(); LoadKnownTypes(); } m_TokenIterator = m_Tokenizer.begin(); m_LineCountIterator = m_TokenIterator; m_uiCurrentLine = 1; for(;;) { const string token = CurrentToken(false); if(IsEndOfFile()) break; // // início de atributos // if(token == "[") { if(m_bParseAsImportFile) { SkipUntilClose("[", "]"); continue; } attributes.clear(); ParseAttributes(&attributes); // // se não for atributo de uma interface vamos ignorar. // Acho melhor do que verificar antes se é uma interface e ter que "rebobinar" // o iterator (o que, na realidade, não é possível pq o iterator é forward-only) // if(CurrentToken() != "interface") attributes.clear(); } else if(token == "cpp_quote") { SkipQuote(); CheckExpectedNextToken(")"); } else if(token == "coclass") { SkipUntilClose("{", "}"); NextToken(); } else if(token == "import") { stringstream stm; CheckExpectedNextToken("""); while(NextToken(true, false) != """) stm << CurrentToken(true, false); ParseImportFile(stm.str()); CheckExpectedNextToken(";"); NextToken(); } else if(token == "#define") { for(;;) { if(NextToken(true, false) == "n") break; // // se for vamos pular um token, pq se o próximo // for um n ele será pulado. Senão não tem efeito mesmo... // if(CurrentToken(true, false) == "") NextToken(true, false); } } else if(token == "interface") { if(m_bParseAsImportFile) { AddKnownInterfaceName(NextTokenAsIdentifier()); if(NextToken() != ";") SkipUntilClose("{", "}"); continue; } IdlInterface iface; if(attributes.empty()) { // // se não tem atributos TEM QUE SER um forward declaration // string name; name = NextTokenAsIdentifier(); CheckExpectedNextToken(";"); NextToken(); m_KnownInterfaces.push_back(name); continue; } // // coloca os atributos encontrados na interface // iface.Attributes = attributes; attributes.clear(); ParseInterface(&iface); AddParsedInterface(iface); } else if(token == "enum") { // // por enquanto só vamos pegar o nome do enum para considerarmos // como um tipo válido // SkipUntilClose("{", "}"); if(NextToken() != ";") { AddKnownType(CurrentTokenAsIdentifier()); CheckExpectedNextToken(";"); } NextToken(); } else { NextToken(false); } } if(!m_bParseAsImportFile) { cout << "Finish (" << g_dwIoTime << " / " << dwTickCount << " / " << std::fixed << percent << ")" << endl; } return; } void MidlParser::AddFindPath(const string& path) { if(std::find(m_IncludePaths.begin(), m_IncludePaths.end(), path) == m_IncludePaths.end()) { if(*path.rbegin() != '') m_IncludePaths.push_back(path + ""); else m_IncludePaths.push_back(path); } } const std::map<string,IdlInterface>& MidlParser::GetParsedInterfaces() const { return m_ParsedInterfaces; } const std::vector<string>& MidlParser::GetKnownInterfaces() const { return m_KnownInterfaces; } // -------------------------------------------------------------------------- // select1st, select2nd // -------------------------------------------------------------------------- #include <boost/call_traits.hpp> template <class Pair> struct select1st : std::unary_function<Pair,typename Pair::first_type> { typename const Pair::first_type& operator()(typename boost::call_traits<Pair>::param_type x) const { return x.first; } }; template <class Pair> struct select2nd : std::unary_function<Pair,typename Pair::second_type> { typename const Pair::second_type& operator()(typename boost::call_traits<Pair>::param_type x) const { return x.second; } }; void MidlParser::Dump(ostream& s) const { s << "KnownInterfaces" << endl << string(30, '=') << endl; std::copy(m_KnownInterfaces.begin(), m_KnownInterfaces.end(), std::ostream_iterator<string>(s, "rn")); s << endl << "ParsedInterfaces" << endl << string(30, '=') << endl; std::copy( boost::make_transform_iterator(m_ParsedInterfaces.begin(), select1st<const std::map<string, IdlInterface>::value_type>()), boost::make_transform_iterator(m_ParsedInterfaces.end(), select1st<const std::map<string, IdlInterface>::value_type>()), std::ostream_iterator<string>(s, "rn")); s.flush(); } void MidlParser::AddKnownType(const string& t) { if(std::find(m_KnownTypes.begin(), m_KnownTypes.end(), t) == m_KnownTypes.end()) { m_KnownTypes.push_back(t); } }
Página feita usando o code@Web, de autoria de Thiago Adams.
Em 11/08/2005 18:56, por Rodrigo Strauss





interessante teu parser, me lembra minhas aulas de compiladores na facul, com gramaticas LR e ai vai cacetada de código...
tua solucao usando C++ puro ficou muito bem feita, principalmente a parte do "tokenizer", facilitou muito o servico...
nao curti tua rotina pra carregar os tipos e interfaces conhecidas, no bom e velho jeitão C de declarar strings fica mais simples e visual, ainda q o boost::assign deu uma ajudada... espero q a nova spec do C++ (C++0x) traga essa funcionalidade para facilitar inicializacoes, coisas do tipo:
list<string> t = { "blah", "blah", "blah" };
pelo menos era esse o objetivo deles... isso facilitaria muito teu codigo:
vector<string> m_KnownInterfaces =
{
"IUnknown",
"IDispatch"
};
o mesmo pra tua maquina de estados, quando fiz eu acabei definindo um id pra cada token, e criei um switch pra levar pra cada proximo estado, nao gosto mto de "else ifs" seguidos, mas dae jah eh gosto pessoal... mais uma vez: espero q no C++0x a funcionalidade de switch para strings esteja presente tambem:
switch( token )
{
case "[":
...
break;
case "cpp_quote":
...
break;
}
uma vez jah pensei em criar uma classe abstrata "Token" e derivar meus tokens, para que os estados fossem atingidos por polimorfismo, talvez eu tente no futuro. daria ateh pra resumir codigo com algum class factory bem feito...
soh nao entendi uma coisa (pode ateh parecer meio estupido, mas nao entendi mesmo): voce lancou varias excecoes no codigo mas ninguem esta capturando, vc quer q pare tudo mesmo ou delega o catch pro usuario do parser?!?