parser.cc
来自「这个程序是关于OpenC++的反射植入机制的编译器」· CC 代码 · 共 3,111 行 · 第 1/5 页
CC
3,111 行
//@beginlicenses@//@license{chiba_tokyo}{}@//@license{contributors}{}@//// Permission to use, copy, distribute and modify this software and its // documentation for any purpose is hereby granted without fee, provided that// the above copyright notice appears in all copies and that both that copyright// notice and this permission notice appear in supporting documentation.// // 1997-2001 Shigeru Chiba, Tokyo Institute of Technology. make(s) no representations about the suitability of this// software for any purpose. It is provided "as is" without express or implied// warranty.// // Copyright (C) 1997-2001 Shigeru Chiba, Tokyo Institute of Technology.//// -----------------------------------------------------------------//// Permission to use, copy, distribute and modify this software and its // documentation for any purpose is hereby granted without fee, provided that// the above copyright notice appears in all copies and that both that copyright// notice and this permission notice appear in supporting documentation.// // Other Contributors (see file AUTHORS) make(s) no representations about the suitability of this// software for any purpose. It is provided "as is" without express or implied// warranty.// // Copyright (C) Other Contributors (see file AUTHORS)////@endlicenses@/* C++ Parser This parser is a LL(k) parser with ad hoc rules such as backtracking. r<name>() is the grammer rule for a non-terminal <name>. opt<name>() is the grammer fule for an optional non-terminal <name>. is<name>() looks ahead and returns true if the next symbol is <name>.*/#include <iostream>#include <opencxx/parser/Parser.h>#include <opencxx/parser/Token.h>#include <opencxx/parser/Lex.h>#include <opencxx/parser/token-names.h>#include <opencxx/parser/ptreeAll.h>#include <opencxx/parser/Encoding.h>#include <opencxx/parser/PtreeUtil.h>#include <opencxx/parser/MopMsg.h>#include <opencxx/parser/ParseErrorMsg.h>#include <opencxx/parser/ErrorLog.h>#include <opencxx/parser/SourceLocation.h>#include <opencxx/parser/NullMetaclassLoader.h>#if defined(_PARSE_VCC)#define _MSC_VER 1100#endifusing namespace std;namespace Opencxx{unsigned Parser::LineNumber(char* pos, char*& fname, int& fname_len){ unsigned line_number = lex->LineNumber(pos, fname, fname_len); if(fname_len > 1){ if(fname[0] == '"') { ++fname; --fname_len; } if(fname[fname_len - 1] == '"') --fname_len; } return line_number;}bool Parser::rProgram(Ptree*& def){ while(lex->LookAhead(0) != '\0') if(rDefinition(def)) return true; else{ Token tk; if(!SyntaxError()) return false; // too many errors SkipTo(';'); lex->GetToken(tk); // ignore ';' } return false;}/* definition : null.declaration | typedef.stmt | template.decl | metaclass.decl | linkage.spec | namespace.spec | namespace.alias | using.declaration | extern.template.decl | declaration*/bool Parser::rDefinition(Ptree*& p){ bool res; int t = lex->LookAhead(0); if(t == ';') res = rNullDeclaration(p); else if(t == TYPEDEF) res = rTypedef(p); else if(t == TEMPLATE) res = rTemplateDecl(p); else if(t == METACLASS) res = rMetaclassDecl(p); else if(t == EXTERN && lex->LookAhead(1) == StringL) res = rLinkageSpec(p); else if(t == EXTERN && lex->LookAhead(1) == TEMPLATE) res = rExternTemplateDecl(p); else if(t == NAMESPACE && lex->LookAhead(2) == '=') res = rNamespaceAlias(p); else if(t == NAMESPACE) res = rNamespaceSpec(p); else if(t == USING) res = rUsing(p); else { Ptree* c = lex->GetComments2(); if (res = rDeclaration(p)) { PtreeUtil::SetDeclaratorComments(p, c); } } lex->GetComments(); return res;}bool Parser::rNullDeclaration(Ptree*& decl){ Token tk; if(lex->GetToken(tk) != ';') return false; decl = new PtreeDeclaration(0, PtreeUtil::List(0, new Leaf(tk))); return true;}/* typedef.stmt : TYPEDEF type.specifier declarators ';'*/bool Parser::rTypedef(Ptree*& def){ Token tk; Ptree *type_name, *decl; Encoding type_encode; if(lex->GetToken(tk) != TYPEDEF) return false; def = new PtreeTypedef(new LeafReserved(tk)); if(!rTypeSpecifier(type_name, false, type_encode)) return false; def = PtreeUtil::Snoc(def, type_name); if(!rDeclarators(decl, type_encode, true)) return false; if(lex->GetToken(tk) != ';') return false; def = PtreeUtil::Nconc(def, PtreeUtil::List(decl, new Leaf(tk))); return true;}/* type.specifier : {cv.qualify} (integral.type.or.class.spec | name) {cv.qualify}*/bool Parser::rTypeSpecifier(Ptree*& tspec, bool check, Encoding& encode){ Ptree *cv_q, *cv_q2; if(!optCvQualify(cv_q) || !optIntegralTypeOrClassSpec(tspec, encode)) return false; if(tspec == 0){ if(check){ Token tk; lex->LookAhead(0, tk); if(!MaybeTypeNameOrClassTemplate(tk)) return false; } if(!rName(tspec, encode)) return false; } if(!optCvQualify(cv_q2)) return false; if(cv_q != 0){ tspec = PtreeUtil::Snoc(cv_q, tspec); if(cv_q2 != 0) tspec = PtreeUtil::Nconc(tspec, cv_q2); } else if(cv_q2 != 0) tspec = PtreeUtil::Cons(tspec, cv_q2); encode.CvQualify(cv_q, cv_q2); return true;}// isTypeSpecifier() returns true if the next is probably a type specifier.bool Parser::isTypeSpecifier(){ int t = lex->LookAhead(0); if(t == Identifier || t == Scope ||t == CONST || t == VOLATILE || t == CHAR || t == INT || t == SHORT || t == LONG || t == WCHAR // new !!! || t == SIGNED || t == UNSIGNED || t == FLOAT || t == DOUBLE || t == VOID || t == BOOLEAN || t == CLASS || t == STRUCT || t == UNION || t == ENUM#if defined(_MSC_VER) || t == INT64#endif ) return true; else return false;}/* metaclass.decl : METACLASS Identifier {{':'} Identifier {'(' meta.arguments ')'}} ';' We allow two kinds of syntax: metaclass <metaclass> <class>(...); metaclass <metaclass>; metaclass <class> : <metaclass>(...); // for backward compatibility*/bool Parser::rMetaclassDecl(Ptree*& decl){ int t; Token tk1, tk2, tk3, tk4; Ptree* metaclass_name; if(lex->GetToken(tk1) != METACLASS) return false; if(lex->GetToken(tk2) != Identifier) return false; t = lex->GetToken(tk3); if(t == Identifier){ metaclass_name = new Leaf(tk2); decl = new PtreeMetaclassDecl(new LeafReserved(tk1), PtreeUtil::List(metaclass_name, new Leaf(tk3))); } else if(t == ':'){ if(lex->GetToken(tk4) != Identifier) return false; metaclass_name = new Leaf(tk4); decl = new PtreeMetaclassDecl(new LeafReserved(tk1), PtreeUtil::List(metaclass_name, new Leaf(tk2))); } else if(t == ';'){ metaclass_name = new Leaf(tk2); decl = new PtreeMetaclassDecl(new LeafReserved(tk1), PtreeUtil::List(metaclass_name, 0, new Leaf(tk3))); metaclassLoader_->LoadMetaclass(metaclass_name->ToString()); return true; } else return false; t = lex->GetToken(tk1); if(t == '('){ Ptree* args; if(!rMetaArguments(args)) return false; if(lex->GetToken(tk2) != ')') return false; decl = PtreeUtil::Nconc(decl, PtreeUtil::List(new Leaf(tk1), args, new Leaf(tk2))); t = lex->GetToken(tk1); } if(t == ';'){ decl = PtreeUtil::Snoc(decl, new Leaf(tk1)); metaclassLoader_->LoadMetaclass(metaclass_name->ToString()); return true; } else return false;}/* meta.arguments : (anything but ')')**/bool Parser::rMetaArguments(Ptree*& args){ int t; Token tk; int n = 1; args = 0; for(;;){ t = lex->LookAhead(0); if(t == '\0') return false; else if(t == '(') ++n; else if(t == ')') if(--n <= 0) return true; lex->GetToken(tk); args = PtreeUtil::Snoc(args, new Leaf(tk)); }}/* linkage.spec : EXTERN StringL definition | EXTERN StringL linkage.body*/bool Parser::rLinkageSpec(Ptree*& spec){ Token tk1, tk2; Ptree* body; if(lex->GetToken(tk1) != EXTERN) return false; if(lex->GetToken(tk2) != StringL) return false; spec = new PtreeLinkageSpec(new LeafEXTERN(tk1), PtreeUtil::List(new Leaf(tk2))); if(lex->LookAhead(0) == '{'){ if(!rLinkageBody(body)) return false; } else if(!rDefinition(body)) return false; spec = PtreeUtil::Snoc(spec, body); return true;}/* namespace.spec : NAMESPACE Identifier definition | NAMESPACE { Identifier } linkage.body*/bool Parser::rNamespaceSpec(Ptree*& spec){ Token tk1, tk2; Ptree* name; Ptree* body; if(lex->GetToken(tk1) != NAMESPACE) return false; if(lex->LookAhead(0) == '{') name = 0; else if(lex->GetToken(tk2) == Identifier) name = new Leaf(tk2); else return false; if(lex->LookAhead(0) == '{'){ if(!rLinkageBody(body)) return false; } else if(!rDefinition(body)) return false; spec = new PtreeNamespaceSpec(new LeafNAMESPACE(tk1), PtreeUtil::List(name, body)); return true;}/* namespace.alias : NAMESPACE Identifier '=' Identifier ';'*/bool Parser::rNamespaceAlias(Ptree *&exp){ Token tk; if(lex->GetToken(tk) != NAMESPACE) return false; Ptree *ns = new LeafNAMESPACE(tk); if (lex->GetToken(tk) != Identifier) return false; Ptree *alias = new Leaf(tk); if (lex->GetToken(tk) != '=') return false; Ptree *eq = new Leaf(tk); Ptree *name; Encoding encode; int length = 0; if(lex->LookAhead(0) == Scope) { lex->GetToken(tk); name = PtreeUtil::List(new Leaf(tk)); encode.GlobalScope(); ++length; } else name = 0; while (true) { if (lex->GetToken(tk) != Identifier) return false; Ptree *n = new Leaf(tk); encode.SimpleName(n); ++length; if(lex->LookAhead(0) == Scope) { lex->GetToken(tk); name = PtreeUtil::Nconc(name, PtreeUtil::List(n, new Leaf(tk))); } else { if(name == 0) name = n; else name = PtreeUtil::Snoc(name, n); if(length > 1) encode.Qualified(length); break; } } if (lex->GetToken(tk) != ';') return false; exp = new PtreeNamespaceAlias(ns, PtreeUtil::List(alias, eq, name, new Leaf(tk))); return true;}/* using.declaration : USING { NAMESPACE } name ';'*/bool Parser::rUsing(Ptree*& decl){ Token tk; Ptree* name; Encoding encode; if(lex->GetToken(tk) != USING) return false; Ptree* using0 = new LeafUSING(tk); Ptree* using1; if (lex->LookAhead(0) != NAMESPACE) using1 = 0; else { lex->GetToken(tk); using1 = new LeafNAMESPACE(tk); } if (!rName(name, encode)) return false; if (lex->GetToken(tk) != ';') return false; decl = new PtreeUsing(using0, using1, name, encode.Get(), new Leaf(tk)); return true;}/* linkage.body : '{' (definition)* '}' Note: this is also used to construct namespace.spec*/bool Parser::rLinkageBody(Ptree*& body){ Token op, cp; Ptree* def; if(lex->GetToken(op) != '{') return false; body = 0; while(lex->LookAhead(0) != '}'){ if(!rDefinition(def)){ if(!SyntaxError()) return false; // too many errors SkipTo('}'); lex->GetToken(cp); body = PtreeUtil::List(new Leaf(op), 0, new Leaf(cp)); return true; // error recovery } body = PtreeUtil::Snoc(body, def); } lex->GetToken(cp); body = new PtreeBrace(new Leaf(op), body, new Leaf(cp)); return true;}/* template.decl : TEMPLATE '<' temp.arg.list '>' declaration | TEMPLATE declaration | TEMPLATE '<' '>' declaration The second case is an explicit template instantiation. declaration must be a class declaration. For example, template class Foo<int, char>; explicitly instantiates the template Foo with int and char. The third case is a specialization of a template function. declaration must be a function template. For example, template <> int count(String x) { return x.length; }*/bool Parser::rTemplateDecl(Ptree*& decl){ Ptree *body; TemplateDeclKind kind = tdk_unknown; if(!rTemplateDecl2(decl, kind)) return false; if(!rDeclaration(body)) return false; // Repackage the decl and body depending upon what kind of template // declaration was observed. switch (kind) { case tdk_instantiation: // Repackage the decl as a PtreeTemplateInstantiation decl = body; // assumes that decl has the form: [0 [class ...] ;] if (PtreeUtil::Length(decl) != 3) return false; if (PtreeUtil::First(decl) != 0) return false; if (PtreeUtil::Second(decl)->What() != ntClassSpec) return false; if (!PtreeUtil::Eq(PtreeUtil::Third(decl), ';')) return false; decl = new PtreeTemplateInstantiation(PtreeUtil::Second(decl)); break; case tdk_decl: case tdk_specialization: decl = PtreeUtil::Snoc(decl, body); break; default: errorLog_.Report(MopMsg(Msg::Fatal, "rTemplateDecl()", "fatal")); break; } return true;}bool Parser::rTemplateDecl2(Ptree*& decl, TemplateDeclKind &kind){ Token tk; Ptree *args; if(lex->GetToken(tk) != TEMPLATE) return false; if(lex->LookAhead(0) != '<') { // template instantiation decl = 0; kind = tdk_instantiation; return true; // ignore TEMPLATE } decl = new PtreeTemplateDecl(new LeafReserved(tk)); if(lex->GetToken(tk) != '<') return false; decl = PtreeUtil::Snoc(decl, new Leaf(tk)); if(!rTempArgList(args)) return false; if(lex->GetToken(tk) != '>') return false; decl = PtreeUtil::Nconc(decl, PtreeUtil::List(args, new Leaf(tk))); // ignore nested TEMPLATE while (lex->LookAhead(0) == TEMPLATE) { lex->GetToken(tk); if(lex->LookAhead(0) != '<') break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?