ultimatepp/uppsrc/CppBase/Parser.cpp
cxl ae24688764 A++: fixed problems with typecast operator, navigator scope double-click goes to the first item
git-svn-id: svn://ultimatepp.org/upp/trunk@609 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-11-05 21:36:41 +00:00

1530 lines
29 KiB
C++

#include "CppBase.h"
NAMESPACE_UPP
#ifdef _MSC_VER
#pragma inline_depth(255)
#pragma optimize("t", on)
#endif
#define LLOG(x) // DLOG(x)
#define LTIMING(x) // TIMING(x)
inline const char *bew(const char *s, const char *t)
{
while(*s)
if(*s++ != *t++)
return NULL;
return t;
}
static String s_operator("operator");
static String s_virtual("virtual");
static String s_inline("inline");
static String s_static("static");
static inline bool sSpaces(String& res, const char *& s)
{
if((byte)*s <= ' ') {
char c = *s++;
if(c != '\2') {
res.Cat(' ');
while((byte)*s <= ' ' && *s)
s++;
}
return true;
}
return false;
}
String FnItem(const char *s, const char *pname, const char *qname, const String& name) {
String res;
while(*s && (byte)*s <= ' ') s++;
while(*s) {
while(*s && !iscid(*s) && *s != '~')
s++;
while(iscid(*s) || *s == '~')
res.Cat(*s++);
if(res == s_operator) {
while(*s && *s != '(') {
if((byte)*s >= ' ')
res.Cat(*s);
s++;
}
break;
}
while(*s && (byte)*s <= ' ')
s++;
if(*s == '(' && (res == name || res == '~' + name))
break;
res.Clear();
}
while(*s) {
const char *w = bew(qname, s);
byte c = *s;
if(w && !iscid(*w)) {
if(iscid(*res.Last()))
res.Cat(' ');
res.Cat(name);
s = w;
}
else
if(iscid(c)) {
const char *b = s++;
while(iscid(*s)) s++;
String q(b, s);
if(q != s_virtual && q != s_inline && q != s_static && !InScList(q, pname)) {
if(iscid(*res.Last()))
res.Cat(' ');
res.Cat(q);
}
else
while((byte)*s <= ' ' && *s) s++;
}
else
if(c == '=') {
s++;
int l = 0;
while(*s && !(l == 0 && (*s == ',' || *s == ')'))) {
if(*s == '(')
l++;
else
if(*s == ')')
l--;
s++;
}
}
else
if((byte)*s <= ' ') {
s++;
while((byte)*s <= ' ' && *s)
s++;
}
else {
res.Cat(c);
s++;
}
}
return res;
}
String Purify(const char *s, const char *qname, const String& name) {
String res;
while(*s && (byte)*s <= ' ') s++;
while(*s) {
const char *w = bew(qname, s);
if(w) {
res.Cat(name);
s = w;
}
else
if(iscid(*s)) {
const char *b = s++;
while(iscid(*s)) s++;
String q(b, s);
if(q != s_virtual && q != s_inline && q != s_static)
res.Cat(q);
else
while((byte)*s <= ' ' && *s) s++;
}
else
if(!sSpaces(res, s))
res.Cat(*s++);
}
return TrimRight(res);
}
String Purify(const char *s) {
String res;
while(*s && (byte)*s <= ' ') s++;
while(*s) {
if(iscid(*s)) {
const char *b = s++;
while(iscid(*s)) s++;
String q(b, s);
if(q != s_virtual && q != s_inline)
res.Cat(q);
else
while((byte)*s <= ' ' && *s) s++;
}
else
if(!sSpaces(res, s))
res.Cat(*s++);
}
return TrimRight(res);
}
String Gpurify(const char *s)
{
String res;
while(*s)
if(!sSpaces(res, s))
res.Cat(*s++);
return res;
}
void ScAdd(String& s, const String& a)
{
if(a.IsEmpty()) return;
if(!s.IsEmpty())
s << ';';
s << a;
}
String Parser::Context::Dump() const
{
return "Scopeing: " + scope;
}
Parser::FunctionStat::FunctionStat(const String & scope,
const CppItem & cppItem,
const LexSymbolStat &symbolStat,
int maxScopeDepth) :
scope(scope), cppItem(cppItem),
symbolStat(symbolStat), maxScopeDepth(maxScopeDepth)
{
}
static String s_dblcln("::");
inline void ScopeCat(String& scope, const String& s)
{
if(scope.GetCount())
scope << s_dblcln;
scope << s;
}
void Parser::Context::operator<<=(const Context& t)
{
scope = t.scope;
typenames <<= t.typenames;
tparam <<= t.tparam;
access = t.access;
ctname = t.ctname;
}
Parser::Decla::Decla()
{
function = type_def = false;
s_static = s_auto = s_register = s_extern = s_mutable = s_explicit = s_virtual = false;
isfriend = istemplate = istructor = isptr = nofn = false;
castoper = false;
}
bool Parser::Key(int code)
{
if(lex == code) {
++lex;
return true;
}
return false;
}
int Parser::GetLine(const char *p)
{
int pos = int(p - ~file.text);
int l = 0;
int h = file.linepos.GetCount();
while(l < h) {
int q = (l + h) / 2;
if(file.linepos[q] < pos)
l = q + 1;
else
h = q;
}
return l;
}
void Parser::Line()
{
int pos = int(lex.Pos() - ~file.text);
while(line + 1 < file.linepos.GetCount() && file.linepos[line + 1] <= pos)
line++;
}
void Parser::ThrowError(const String& e)
{
err(GetLine(lex.Pos()), e);
#ifdef _DEBUG
int i = 0;
while(i < 40 && lex[i] != t_eof)
i++;
LLOG("ERROR: (" << GetLine(lex.Pos()) << ") " << e << ", scope: " << current_scope <<
" " << AsCString(String(lex.Pos(), lex.Pos(i))));
#endif
throw Error();
}
void Parser::Check(bool b, const char *err)
{
if(!b) ThrowError(err);
}
void Parser::CheckKey(int c)
{
if(!Key(c)) ThrowError(Format("Missing %c", c));
}
String Parser::TemplateParams(String& param)
{
const char *pos = lex.Pos();
CheckKey('<');
int level = 1;
String id;
bool gp = true;
while(lex != t_eof) {
if(lex.IsId() && gp)
id = lex.GetId();
else
if(Key(',')) {
ScAdd(param, id);
id.Clear();
gp = true;
}
else
if(Key('=')) {
if(!id.IsEmpty()) {
ScAdd(param, id);
id.Clear();
}
gp = false;
}
else
if(Key('>')) {
level--;
if(level <= 0) {
ScAdd(param, id);
break;
}
}
else
if(Key('<'))
level++;
else
++lex;
}
return String(pos, lex.Pos());
}
String Parser::TemplateParams()
{
String dummy;
return TemplateParams(dummy);
}
String Parser::TemplatePnames()
{
String pnames;
TemplateParams(pnames);
return pnames;
}
String Parser::ReadOper(bool& castoper) {
const char *p = lex.Pos();
Key(tk_operator);
int level = 0;
if(Key('('))
level++;
for(;;) {
if(lex == t_eof || level <= 0 && lex == '(') break;
if(Key('(') || Key('[')) level++;
else
if(Key(')') || Key(']')) level--;
else
++lex;
}
StringBuffer r;
bool spc = false;
while(p < lex.Pos()) {
if((byte)*p > ' ') {
if(spc && iscid(*p)) {
castoper = true;
r.Cat(' ');
}
r.Cat(*p);
spc = false;
}
else
spc = true;
p++;
}
return r;
}
String Parser::Name(String& name, bool& castoper)
{
String s;
if(Key(t_dblcolon)) {
s = "::";
name = s;
}
Check(lex.IsId() || lex == tk_operator, "Name expected");
for(;;) {
if(lex.IsId()) {
name << lex.Id();
s << lex.GetId();
}
else {
String h = ReadOper(castoper);
name << h;
s << h;
break;
}
if(lex == '<')
s << TemplateParams();
if(Key(t_dblcolon)) {
s << "::";
name << "::";
if(Key('~')) {
s << "~";
name << "~";
}
}
else
break;
}
return s;
}
String Parser::Name(bool& castoper)
{
String h;
return Name(h, castoper);
}
String Parser::Constant()
{
const char *p = lex.Pos();
const char *p1 = p;
int level = 0;
for(;;) {
p1 = lex.Pos();
if(lex == t_eof) break;
if(level <= 0 && (lex == ',' || lex == ';' || lex == ')' || lex == '}' || lex == ']'))
break;
if(Key('(') || Key('[') || Key('{')) level++;
else
if(Key(')') || Key(']') || Key('}')) level--;
else
++lex;
}
return String(p, p1);
}
String Parser::TType()
{
int q = FindIndex(context.tparam, lex[0]);
if(q >= 0) return AsString(q);
return lex.Id();
}
String Parser::SimpleType(Decla& d)
{
Key(tk_typename) || Key(tk_struct) || Key(tk_class) || Key(tk_union) || Key(tk_enum);
if(Key(tk_bool) || Key(tk_float) || Key(tk_double) || Key(tk_void))
return Null;
bool sgn = Key(tk_signed) || Key(tk_unsigned);
if(Key(tk_long)) {
Key(tk_long);
Key(tk_int) || Key(tk_double);
return Null;
}
if(Key(tk_short)) {
Key(tk_unsigned);
Key(tk_int);
return Null;
}
if(Key(tk_int) || Key(tk_char) ||
Key(tk___int8) || Key(tk___int16) || Key(tk___int32) || Key(tk___int64)) return Null;
if(sgn) return Null;
const char *p = lex.Pos();
bool cs = false;
Index<int> cix;
if(Key(t_dblcolon))
d.type << "::";
Check(lex.IsId(), "Name expected");
while(lex.IsId()) {
d.type << TType();
if(cix.Find(lex) >= 0)
cs = true;
else
cix.Add(lex);
++lex;
if(lex == '<')
d.type << TemplateParams();
if(Key(t_dblcolon)) {
d.type << "::";
if(Key('~'))
cs = true;
}
else
break;
}
return cs ? String(p, lex.Pos()) : String();
}
void Parser::Qualifier()
{
Key(tk_const);
Key(tk_volatile);
if(Key(tk_throw)) {
while(lex != t_eof && !Key(')'))
++lex;
}
}
void Parser::Elipsis(Decl& d)
{
Decl& q = d.param.Add();
q.name = "...";
CheckKey(')');
}
void Parser::ParamList(Decl& d) {
if(!Key(')'))
for(;;) {
if(Key(t_elipsis)) {
Elipsis(d);
break;
}
else
d.param.Add() = Declaration().Top();
if(Key(t_elipsis)) {
Elipsis(d);
break;
}
if(Key(')')) break;
CheckKey(',');
}
}
int Parser::RPtr()
{
int n = 0;
int tlevel = 0;
for(;;) {
int t = lex[n];
if(t == '*') return n + 1;
if(t == '<') {
tlevel++;
n++;
}
else
if(t == '>') {
tlevel--;
n++;
}
else
if(t == t_dblcolon || lex.IsId(n) || t == ',' && tlevel > 0)
n++;
else
return 0;
}
}
void Parser::EatInitializers()
{
if(Key(':'))
while(lex != '{' && lex != t_eof)
++lex;
}
void Parser::Declarator(Decl& d, const char *p)
{
int n = RPtr();
if(n) {
while(n--) lex.Get();
Declarator(d, p);
d.isptr = true;
return;
}
if(Key('&')) {
Declarator(d, p);
return;
}
if(Key(tk_const)) {
Declarator(d, p);
return;
}
if(Key('(')) {
Declarator(d, p);
if(d.isptr)
d.nofn = true;
CheckKey(')');
}
// if(lex == tk_operator)
// d.name = ReadOper();
// else
if(lex.IsId() || lex == t_dblcolon || lex == tk_operator) {
d.name = Name(d.castoper);
bool dummy;
if(Key(':'))
if(!Key(t_integer))
Name(dummy);
}
if(Key('(')) {
if(inbody || (lex < 256 || lex == tk_true || lex == tk_false)
&& lex != ')' && lex != t_dblcolon) {
int level = 0;
for(;;) {
if(lex == t_eof) break;
if(Key('(')) level++;
else
if(Key(')')) {
if(--level < 0) break;
}
else
++lex;
}
return;
}
else {
d.function = !d.nofn;
ParamList(d);
p = lex.Pos();
Qualifier();
}
}
EatInitializers();
while(Key('[')) {
d.isptr = true;
int level = 1;
while(level && lex != t_eof) {
if(Key('[')) level++;
else
if(Key(']')) level--;
else
++lex;
}
}
if(Key('=') || (inbody && lex == '(')) {
int level = 0;
for(;;) {
if(lex == t_eof || level == 0 && (lex == ',' || lex == ')' || lex == ';'))
break;
if(Key('(') || Key('{'))
level++;
else
if(Key(')') || Key('}'))
level--;
else
++lex;
}
}
}
Parser::Decl& Parser::Finish(Decl& d, const char *s)
{
d.natural = String(s, lex.Pos());
return d;
}
Parser::Decl Parser::Type() {
Decl d;
const char *p = lex.Pos();
Qualifier();
SimpleType(d);
Declarator(d, p);
return Finish(d, p);
}
bool Parser::IsParamList(int q)
{
return true;
}
Array<Parser::Decl> Parser::Declaration0(bool l0, bool more)
{
Array<Decl> r;
Decla d;
const char *p = lex.Pos();
if(Key(tk_friend))
d.isfriend = true;
for(;;) {
if(Key(tk_static))
d.s_static = true;
else
if(Key(tk_extern))
d.s_extern = true;
else
if(Key(tk_auto))
d.s_auto = true;
else
if(Key(tk_register))
d.s_register = true;
else
if(Key(tk_mutable))
d.s_mutable = true;
else
if(Key(tk_explicit))
d.s_explicit = true;
else
if(Key(tk_virtual))
d.s_virtual = true;
else
if(!Key(tk_inline))
break;
}
Qualifier();
bool isdestructor = Key('~');
if(l0 && context.typenames.Find(lex) >= 0 && lex[1] == '(' && lex.IsId()) {
Decl& a = r.Add();
a.name = lex.GetId();
a.isdestructor = isdestructor;
a.function = true;
a.istructor = true;
++lex;
ParamList(a);
Qualifier();
a.natural = String(p, lex.Pos());
EatInitializers();
return r;
}
if(lex == tk_operator) {
Decl& a = r.Add();
(Decla&)a = d;
a.name = ReadOper(a.castoper);
Key('(');
ParamList(a);
Qualifier();
a.function = true;
a.natural = String(p, lex.Pos());
return r;
}
String st = SimpleType(d);
if(!st.IsEmpty()) {
Decl& a = r.Add();
a.name = st;
a.isdestructor = st.Find('~') > 0;
a.function = true;
a.istructor = true;
if(Key('('))
ParamList(a);
Qualifier();
a.natural = String(p, lex.Pos());
EatInitializers();
return r;
}
String natural1 = String(p, lex.Pos());
do {
const char *p1 = lex.Pos();
Decl& a = r.Add();
(Decla&)a = d;
Declarator(a, p);
if(a.castoper)
a.name = Filter(natural1, CharFilterNotWhitespace) + a.name;
a.natural = natural1 + String(p1, lex.Pos());
p = lex.Pos();
}
while(more && Key(','));
return r;
}
Array<Parser::Decl> Parser::Declaration(bool l0, bool more)
{
if(Key(tk_typedef)) {
Array<Decl> r = Declaration(false, true);
for(int i = 0; i < r.GetCount(); i++) {
r[i].type_def = true;
r[i].natural = "typedef " + r[i].natural;
}
return r;
}
return Declaration0(l0, more);
}
void Parser::Locals(const String& type)
{
Array<Parser::Decl> d = Declaration(true, true);
for(int i = 0; i < d.GetCount(); i++) {
Local& l = local.Add(d[i].name);
l.type = type;
l.isptr = d[i].isptr;
}
}
String Parser::Tparam(int& q)
{
if(lex[q] != '<')
return Null;
const char *p = lex.Pos(q);
int level = 1;
q++;
while(lex[q] != t_eof && level) {
if(lex[q] == '<')
level++;
if(lex[q] == '>')
level--;
q++;
}
return String(p, lex.Pos(q));
}
String NoTemplatePars(const String& s)
{
int q = s.Find('<');
return q >= 0 ? s.Mid(0, q) : s;
}
bool Parser::TryDecl()
{
int q = 0;
while(lex[0] == tk_static || lex[0] == tk_const || lex[0] == tk_auto ||
lex[0] == tk_register || lex[0] == tk_volatile)
++lex;
int t = lex[q];
if(t == tk_int || t == tk_bool || t == tk_float || t == tk_double || t == tk_void ||
t == tk_long || t == tk_signed || t == tk_unsigned || t == tk_short ||
t == tk_char || t == tk___int8 || t == tk___int16 || t == tk___int32 || t == tk___int64) {
while(lex[q] == '*' || lex[q] == '&')
q++;
if(!lex.IsId(q))
return false;
Locals(Null);
return true;
}
String type;
if(lex[q] == t_dblcolon) {
type << "::";
q++;
}
if(lex.IsId(q)) {
type << lex.Id(q++);
type << Tparam(q);
}
else
return false;
while(lex[q] == t_dblcolon) {
type << "::";
if(lex.IsId(++q))
type << lex.Id(q++);
else
return false;
type << Tparam(q);
}
while(lex[q] == '*' || lex[q] == '&')
q++;
if(!lex.IsId(q))
return false;
type = Qualify(*base, current_scope, type);
if(base->Find(NoTemplatePars(type)) >= 0) {
Locals(type);
return true;
}
return false;
}
void Parser::MatchPars()
{
int level = 1;
while(level && lex != t_eof) {
if(Key('(')) level++;
else
if(Key(')')) level--;
else
++lex;
}
}
void Parser::Statement()
{
RecursionCounter recursionCounter(currentScopeDepth, lex == '{' ? 0 : 1);
maxScopeDepth = max(maxScopeDepth, currentScopeDepth);
if(Key(tk_case)) {
if(lex.IsId())
++lex;
Key(':');
}
if(Key(tk_default))
Key(':');
if(lex.IsId() && lex[1] == ':') {
++lex;
++lex;
}
if(Key('{')) {
int l = local.GetCount();
while(!Key('}')) {
if(lex == t_eof)
ThrowError("");
Statement();
}
local.Trim(l);
}
else
if(Key(tk_if)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
if(Key(tk_else))
Statement();
local.Trim(l);
}
else
if(Key(tk_for)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(Key(tk_while)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(Key(tk_try))
Statement();
else
if(Key(tk_catch)) {
Key('(');
MatchPars();
Statement();
}
else
if(Key(tk_do)) {
Statement();
Key(tk_while);
Key('(');
MatchPars();
}
else
if(Key(tk_switch)) {
int l = local.GetCount();
Key('(');
TryDecl();
MatchPars();
Statement();
local.Trim(l);
}
else
if(TryDecl())
Key(';');
else
for(;;) {
if(lex == t_eof)
ThrowError("");
if(Key(';') || lex == '{' || lex == '}' || lex >= tk_if && lex <= tk_do)
break;
++lex;
}
}
bool Parser::EatBody()
{
if(lex != '{') {
local.Clear();
return false;
}
lex.BeginBody();
maxScopeDepth = currentScopeDepth = dobody ? 0 : 1;
if(dobody) {
inbody = true;
Statement();
inbody = false;
local.Clear();
}
else {
Key('{');
int level = 1;
while(level && lex != t_eof) {
if(Key('{')) level++;
else
if(Key('}')) level--;
else
++lex;
maxScopeDepth = max(level, maxScopeDepth);
}
}
lex.EndBody();
return true;
}
String CleanTp(const String& tp)
{
int q = tp.Find('<');
int w = tp.ReverseFind('>');
if(q < 0 || w < 0) return tp;
String a = TrimLeft(TrimRight(tp.Mid(q + 1, w - q - 1)));
const char *s = a;
String r;
while(*s) {
if(*s == ',') {
r.Cat(';');
s++;
while(*s && *s <= ' ')
s++;
}
else
r.Cat(*s++);
}
return r;
}
void Parser::SetScopeCurrent()
{
current_scope = context.scope;
}
CppItem& Parser::Item(const String& scope, const String& item, const String& name, bool impl)
{
current_scope = scope;
if(dobody)
current = CppItem();
current_key = item;
current_name = name;
Array<CppItem>& n = base->GetAdd(current_scope);
CppItem& im = dobody ? current : n.Add();
im.item = item;
im.name = name;
im.file = filei;
im.line = line + 1;
im.impl = impl;
im.filetype = filetype;
LLOG("New item " << GetCppFile(filei) << ' ' << line + 1 << " " << scope << "::" << item);
return im;
}
CppItem& Parser::Item(const String& scope, const String& item, const String& name)
{
String h = Purify(item);
CppItem& im = Item(scope, h, name, false);
im.natural = h;
return im;
}
void Parser::Resume(int bl)
{
for(;;) {
if(lex == t_eof || lex.GetBracesLevel() == bl && lex == ';')
break;
++lex;
}
}
void Parser::ScopeBody()
{
int bl = lex.GetBracesLevel();
while(!Key('}')) {
if(lex == t_eof)
ThrowError("Unexpected end of file");
try {
Do();
}
catch(Error) {
Resume(bl);
Key(';');
}
}
}
void TpSkip(CParser& p)
{
int lvl = 0;
for(;;) {
if(lvl == 0 && (p.IsChar(',') || p.IsChar('>')) || p.IsEof())
break;
if(p.Char('<'))
lvl++;
else
if(p.Char('>'))
lvl--;
else
p.SkipTerm();
}
}
String Subst(const String& s, const Vector<String>& tpar)
{
if(tpar.GetCount() == 0)
return s;
String r;
CParser p(s);
while(!p.IsEof()) {
if(p.IsId()) {
String id = p.ReadId();
int q = FindIndex(tpar, id);
if(q >= 0)
r << AsString(q);
else
r << id;
}
else
r << p.GetChar();
}
return r;
}
bool Parser::Scope(const String& tp, const String& tn) {
if(Key(tk_namespace)) {
Check(lex.IsId(), "Expected name of namespace");
String name = lex.GetId();
if(Key('{')) {
Context cc;
cc <<= context;
ScopeBody();
context <<= cc;
}
Key(';');
SetScopeCurrent();
return true;
}
if((lex == tk_class || lex == tk_struct || lex == tk_union) && lex[1] != '{') {
int t = lex.GetCode();
context.typenames.FindAdd(lex);
Context cc;
cc <<= context;
CParser p(tp);
Vector<String> tpar;
if(p.Char('<')) {
while(!p.IsEof() && !p.Char('>')) {
if((p.Id("class") || p.Id("typename") || p.Id("struct")) && p.IsId()) {
tpar.Add(p.ReadId());
context.tparam.Add(lex.Id(tpar.Top()));
}
else
context.tparam.Add(0);
TpSkip(p);
p.Char(',');
}
}
if(Key(t_dblcolon))
context.scope = Null;
String name;
do {
Check(lex.IsId(), "Missing identifier");
context.typenames.FindAdd(lex);
name = lex.GetId();
ScopeCat(context.scope, name);
}
while(Key(t_dblcolon));
context.access = t == tk_class ? PRIVATE : PUBLIC;
if(tn.GetCount()) {
if(context.ctname.GetCount())
context.ctname << ';';
context.ctname << tn;
}
String nn;
if(!tp.IsEmpty())
nn = "template " + tp + " ";
String key = (t == tk_class ? "class" : t == tk_union ? "union" : "struct");
nn << key << ' ' << name;
CppItem& im = Item(context.scope, key, name, lex != ';');
im.kind = tp.IsEmpty() ? STRUCT : STRUCTTEMPLATE;
im.type = name;
im.access = cc.access;
im.tname = tn;
im.ctname = context.ctname;
im.tparam = CleanTp(tp);
im.ptype.Clear();
im.pname.Clear();
im.param.Clear();
if(Key(';')) {
context = cc;
im.natural = Gpurify(nn);
SetScopeCurrent();
return true;
}
if(Key(':')) {
nn << " : ";
bool c = false;
do {
String access = t == tk_class ? "private" : "public";
if(Key(tk_public)) access = "public";
else
if(Key(tk_protected)) access = "protected";
else
if(Key(tk_private)) access = "private";
if(Key(tk_virtual)) access << " virtual";
String h;
bool dummy;
String n = Name(h, dummy);
ScAdd(im.pname, h);
if(c)
im.ptype << ';';
im.ptype << Subst(n, tpar);
ScAdd(im.param, access + ' ' + n);
if(c)
nn << ", ";
nn << access + ' ' + n;
c = true;
}
while(Key(','));
}
if(Key('{')) {
ScopeBody();
im.natural = Gpurify(nn);
im.decla = true;
}
else
if(IsNull(im.natural))
im.natural = Gpurify(nn);
context = cc;
CheckKey(';');
SetScopeCurrent();
return true;
}
return false;
}
String DeTemp(const char *s)
{
String r;
return r;
}
CppItem& Parser::Fn(const Decl& d, const String& templ, bool body,
const String& tname, const String& tparam)
{
String param;
String pname;
String ptype;
for(int i = 0; i < d.param.GetCount(); i++) {
const Decla& p = d.param[i];
if(dobody) {
Local& l = local.Add(p.name);
l.type = p.type;
l.isptr = p.isptr;
}
ScAdd(param, p.natural);
if(i)
ptype << ';';
ptype << p.type;
ScAdd(pname, p.name);
}
String nn0;
String nm = d.name;
int q;
if(d.castoper) {
q = d.name.ReverseFind(' ');
q = q > 0 ? d.name.ReverseFind(':', q) : q = d.name.ReverseFind(':');
}
else
q = d.name.ReverseFind(':');
if(q >= 0) {
nm = d.name.Mid(q + 1);
if(q > 0)
nn0 = d.name.Mid(0, q - 1);
}
String item = FnItem(d.natural, pname, d.name, nm);
String scope = context.scope;
String nn;
const char *s = nn0;
int l = 0;
while(*s) {
if(*s == '<')
l++;
else
if(*s == '>')
l--;
else
if(l == 0)
nn.Cat(*s);
s++;
}
s = nn;
while(*s == ':') s++;
if(*s)
ScopeCat(scope, s);
CppItem& im = Item(scope, item, nm, body);
im.natural.Clear();
if(!IsNull(templ)) {
im.natural = TrimRight(Gpurify(templ)) + ' ';
im.at = im.natural.GetLength();
}
im.natural << Purify(d.natural, d.name, nm);
im.kind = templ.GetCount() ? IsNull(scope) ? FUNCTIONTEMPLATE
: d.s_static ? CLASSFUNCTIONTEMPLATE
: INSTANCEFUNCTIONTEMPLATE
: d.istructor ? (d.isdestructor ? DESTRUCTOR : CONSTRUCTOR)
: d.isfriend ? INLINEFRIEND
: IsNull(scope) ? FUNCTION
: d.s_static ? CLASSFUNCTION
: INSTANCEFUNCTION;
im.param = param;
im.pname = pname;
im.ptype = ptype;
im.access = context.access;
im.virt = d.s_virtual;
im.type = d.type;
im.decla = true;
im.tname = tname;
im.tparam = tparam;
im.ctname = context.ctname;
LLOG("FnItem: " << scope << "::" << item << ", natural: " << im.natural
<< ", ctname: " << im.ctname);
return im;
}
void Parser::Do()
{
LLOG("Do, scope: " << current_scope);
Line();
if(Key(tk_using)) {
while(!Key(';') && lex != t_eof)
++lex;
}
else
if(Key(tk_extern) && lex == t_string) {
++lex;
++lex;
if(Key('{')) {
int bl = lex.GetBracesLevel();
while(lex != '}')
try {
if(lex == t_eof)
ThrowError("Unexpected end of file");
Do();
}
catch(Error) {
Resume(bl);
}
}
Key(';');
}
else
if(Key(tk_template)) {
if(lex.IsId() || lex == tk_class && lex.IsId(1)) {
Key(tk_class);
for(;;) {
if(lex.IsId())
lex.GetId();
else
if(!Key(t_dblcolon))
break;
}
TemplateParams();
Key(';');
}
else {
String tnames;
String tparam = TemplateParams(tnames);
if(!Scope(tparam, tnames)) {
Array<Decl> r = Declaration(true, true);
CppItem *functionItem = 0;
bool body = lex == '{';
for(int i = 0; i < r.GetCount(); i++) {
Decl& d = r[i];
if(!d.isfriend && d.function) {
CppItem& m = Fn(d, "template " + tparam + ' ', body, tnames, tparam);
functionItem = &m;
}
}
if(body && functionItem && whenFnEnd) {
symbolsOutsideFunctions.Merge( lex.FinishStatCollection() );
lex.StartStatCollection(); // start collection of function symbols
}
EatBody();
if(body && functionItem && whenFnEnd) {
whenFnEnd(FunctionStat(current_scope, *functionItem,
lex.FinishStatCollection(), maxScopeDepth));
lex.StartStatCollection(); // start collection of orphan symbols
}
Key(';');
}
EatBody();
}
}
else
if(lex == tk_enum && (lex[1] == '{' || lex[2] == '{')) {
++lex;
String name;
if(lex.IsId())
name = lex.GetId();
if(Key('{')) {
for(;;) {
Line();
String val;
Check(lex.IsId(), "Expected identifier");
String id = lex.GetId();
CppItem& im = Item(context.scope, id, id);
im.natural = "enum ";
if(!IsNull(name))
im.natural << name << ' ';
im.natural << id;
if(Key('='))
im.natural << " = " << Constant();
im.kind = ENUM;
im.access = context.access;
Key(',');
if(Key('}')) break;
}
}
Key(';');
SetScopeCurrent();
}
else
if(Key('#')) {
if(lex.Code() == t_string) {
String n = lex.GetText();
String name;
const char *s = n;
while(*s && iscid(*s))
name.Cat(*s++);
CppItem& im = Item(context.scope, n, name);
im.kind = MACRO;
s = strchr(n, '(');
if(s) {
s++;
String p;
for(;;) {
if(iscid(*s))
p.Cat(*s++);
else {
ScAdd(im.pname, p);
p.Clear();
if(*s == ')' || *s == '\0') break;
s++;
}
}
}
im.access = context.access;
}
}
else
if(!Scope(String(), String())) {
if(Key(tk_public)) {
context.access = PUBLIC;
Key(':');
}
else
if(Key(tk_private)) {
context.access = PRIVATE;
Key(':');
}
else
if(Key(tk_protected)) {
context.access = PROTECTED;
Key(':');
}
else {
Array<Decl> r = Declaration(true, true);
CppItem *functionItem = 0;
bool body = lex == '{';
for(int i = 0; i < r.GetCount(); i++) {
Decl& d = r[i];
if(d.function) {
if(!d.isfriend) {
CppItem &im = Fn(d, Null, body, String(), String());
functionItem = &im;
}
}
else {
String h = d.natural;
int q = h.Find('=');
if(q >= 0)
h = TrimRight(h.Mid(0, q));
String scope = context.scope;
if(d.type_def)
ScopeCat(scope, d.name);
CppItem& im = Item(scope, d.isfriend ? "friend class"
: d.type_def ? "typedef"
: d.name, d.name);
im.natural = Purify(h);
im.type = d.type;
im.access = context.access;
im.kind = d.isfriend ? FRIENDCLASS :
d.type_def ? TYPEDEF :
IsNull(scope) ? VARIABLE :
d.s_static ? CLASSVARIABLE : INSTANCEVARIABLE;
if(im.IsData())
im.isptr = d.isptr;
}
}
if(body && functionItem && whenFnEnd) {
symbolsOutsideFunctions.Merge( lex.FinishStatCollection() );
lex.StartStatCollection(); // start collection of function symbols
}
EatBody();
if(body && functionItem && whenFnEnd) {
whenFnEnd(FunctionStat(current_scope, *functionItem,
lex.FinishStatCollection(), maxScopeDepth));
lex.StartStatCollection(); // start collection of orphan symbols
}
SetScopeCurrent();
Key(';');
}
}
}
void Parser::Do(Stream& in, const Vector<String>& ignore, CppBase& _base, const String& fn,
Callback2<int, const String&> _err, const Vector<String>& typenames)
{
LLOG("= C++ Parser ==================================== " << fn);
base = &_base;
file = PreProcess(in);
lex.Init(~file.text, ignore);
err = _err;
filei = GetCppFileIndex(fn);
String ext = ToLower(GetFileExt(fn));
if(ext == ".h")
filetype = FILE_H;
else
if(ext == ".hpp")
filetype = FILE_HPP;
else
if(ext == ".cpp")
filetype = FILE_CPP;
else
if(ext == ".c")
filetype = FILE_C;
else
filetype = FILE_OTHER;
lpos = 0;
line = 0;
if(whenFnEnd)
lex.StartStatCollection();
while(lex != t_eof)
try {
try {
current_scope.Clear();
context.access = PUBLIC;
context.typenames.Clear();
context.tparam.Clear();
context.scope.Clear();
inbody = false;
for(int i = 0; i < typenames.GetCount(); i++)
context.typenames.Add(lex.Id(typenames[i]));
Do();
}
catch(Error) {
if(lex.IsBody()) {
LLOG("---- Recovery to next ';'");
Resume(lex.GetBracesLevel());
Key(';');
}
else {
LLOG("---- Recovery to file level");
++lex;
lex.SkipToGrounding();
lex.ClearBracesLevel();
}
}
}
catch(Lex::Grounding) {
LLOG("---- Grounding to file level");
lex.ClearBracesLevel();
lex.ClearBody();
}
}
void Parse(Stream& s, const Vector<String>& ignore, CppBase& base, const String& fn,
Callback2<int, const String&> _err)
{
LTIMING("Parse");
Parser p;
p.Do(s, ignore, base, fn, _err);
}
END_UPP_NAMESPACE