summaryrefslogtreecommitdiffstats
path: root/src/docparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/docparser.cpp')
-rw-r--r--src/docparser.cpp227
1 files changed, 185 insertions, 42 deletions
diff --git a/src/docparser.cpp b/src/docparser.cpp
index 2f9bda7..42919fd 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -69,13 +69,14 @@ static uint g_includeFileOffset;
static uint g_includeFileLength;
// parser state
-static QString g_context;
+static QString g_context;
static bool g_inSeeBlock;
static bool g_insideHtmlLink;
static QStack<DocNode> g_nodeStack;
static QStack<DocStyleChange> g_styleStack;
+static QStack<DocStyleChange> g_initialStyleStack;
static QList<Definition> g_copyStack;
-static QString g_fileName;
+static QString g_fileName;
struct DocParserContext
{
@@ -84,6 +85,7 @@ struct DocParserContext
bool insideHtmlLink;
QStack<DocNode> nodeStack;
QStack<DocStyleChange> styleStack;
+ QStack<DocStyleChange> initialStyleStack;
QList<Definition> copyStack;
MemberDef *memberDef;
QString fileName;
@@ -96,27 +98,29 @@ static QStack<DocParserContext> g_parserStack;
static void docParserPushContext()
{
doctokenizerYYpushContext();
- DocParserContext *ctx = new DocParserContext;
- ctx->context = g_context;
- ctx->inSeeBlock = g_inSeeBlock;
- ctx->insideHtmlLink = g_insideHtmlLink;
- ctx->nodeStack = g_nodeStack;
- ctx->styleStack = g_styleStack;
- ctx->copyStack = g_copyStack;
- ctx->fileName = g_fileName;
+ DocParserContext *ctx = new DocParserContext;
+ ctx->context = g_context;
+ ctx->inSeeBlock = g_inSeeBlock;
+ ctx->insideHtmlLink = g_insideHtmlLink;
+ ctx->nodeStack = g_nodeStack;
+ ctx->styleStack = g_styleStack;
+ ctx->initialStyleStack = g_initialStyleStack;
+ ctx->copyStack = g_copyStack;
+ ctx->fileName = g_fileName;
g_parserStack.push(ctx);
}
static void docParserPopContext()
{
DocParserContext *ctx = g_parserStack.pop();
- g_context = ctx->context;
- g_inSeeBlock = ctx->inSeeBlock;
- g_insideHtmlLink = ctx->insideHtmlLink;
- g_nodeStack = ctx->nodeStack;
- g_styleStack = ctx->styleStack;
- g_copyStack = ctx->copyStack;
- g_fileName = ctx->fileName;
+ g_context = ctx->context;
+ g_inSeeBlock = ctx->inSeeBlock;
+ g_insideHtmlLink = ctx->insideHtmlLink;
+ g_nodeStack = ctx->nodeStack;
+ g_styleStack = ctx->styleStack;
+ g_initialStyleStack = ctx->initialStyleStack;
+ g_copyStack = ctx->copyStack;
+ g_fileName = ctx->fileName;
delete ctx;
doctokenizerYYpopContext();
}
@@ -296,7 +300,7 @@ static void checkUndocumentedParams()
"Warning: The following parameters of "+
scope + QString(g_memberDef->name()) +
QString(argListToString(al)) +
- " are not documented:";
+ " are not documented:\n";
for (ali.toFirst();(a=ali.current());++ali)
{
QString argName = g_memberDef->isDefine() ? a->type : a->name;
@@ -559,6 +563,9 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
) ? tok : RetVal_OK;
}
+/*! Called when a style change starts. For instance a \<b\> command is
+ * encountered.
+ */
static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
DocStyleChange::Style s,const HtmlAttribList *attribs)
{
@@ -568,6 +575,9 @@ static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
g_styleStack.push(sc);
}
+/*! Called when a style change ends. For instance a \</b\> command is
+ * encountered.
+ */
static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
DocStyleChange::Style s,const char *tagName)
{
@@ -577,8 +587,16 @@ static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag without matching <%s> in the same paragraph",
- tagName,tagName);
+ if (g_styleStack.isEmpty())
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag without matching <%s>",
+ tagName,tagName);
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag while expecting </%s>",
+ tagName,g_styleStack.top()->styleString());
+ }
}
else // end the section
{
@@ -588,6 +606,10 @@ static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
}
}
+/*! Called at the end of a paragraph to close all open style changes
+ * (e.g. a <b> without a </b>). The closed styles are pushed onto a stack
+ * and entered again at the start of a new paragraph.
+ */
static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
{
if (!g_styleStack.isEmpty())
@@ -595,27 +617,53 @@ static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
DocStyleChange *sc = g_styleStack.top();
while (sc && sc->position()>=g_nodeStack.count())
{ // there are unclosed style modifiers in the paragraph
- const char *cmd="";
- switch (sc->style())
- {
- case DocStyleChange::Bold: cmd = "b"; break;
- case DocStyleChange::Italic: cmd = "em"; break;
- case DocStyleChange::Code: cmd = "code"; break;
- case DocStyleChange::Center: cmd = "center"; break;
- case DocStyleChange::Small: cmd = "small"; break;
- case DocStyleChange::Subscript: cmd = "subscript"; break;
- case DocStyleChange::Superscript: cmd = "superscript"; break;
- case DocStyleChange::Preformatted: cmd = "pre"; break;
- }
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: end of paragraph without end of style "
- "command </%s>",cmd);
children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
+ g_initialStyleStack.push(sc);
g_styleStack.pop();
sc = g_styleStack.top();
}
}
}
+static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
+{
+ DocStyleChange *sc;
+ while ((sc=g_initialStyleStack.pop()))
+ {
+ handleStyleEnter(parent,children,sc->style(),&sc->attribs());
+ }
+}
+
+const char *DocStyleChange::styleString() const
+{
+ switch (m_style)
+ {
+ case DocStyleChange::Bold: return "b";
+ case DocStyleChange::Italic: return "em";
+ case DocStyleChange::Code: return "code";
+ case DocStyleChange::Center: return "center";
+ case DocStyleChange::Small: return "small";
+ case DocStyleChange::Subscript: return "subscript";
+ case DocStyleChange::Superscript: return "superscript";
+ case DocStyleChange::Preformatted: return "pre";
+ }
+ return "<invalid>";
+}
+
+static void handleUnclosedStyleCommands()
+{
+ if (!g_initialStyleStack.isEmpty())
+ {
+ DocStyleChange *sc = g_initialStyleStack.top();
+ g_initialStyleStack.pop();
+ handleUnclosedStyleCommands();
+ warn_doc_error(g_fileName,doctokenizerYYlineno,
+ "Warning: end of comment block while expecting "
+ "command </%s>",sc->styleString());
+ }
+}
+
+
static void handleLinkedWord(DocNode *parent,QList<DocNode> &children)
{
Definition *compound=0;
@@ -828,13 +876,13 @@ static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children
{
handleStyleEnter(parent,children,DocStyleChange::Preformatted,&g_token->attribs);
parent->setInsidePreformatted(TRUE);
- doctokenizerYYsetInsidePre(TRUE);
+ //doctokenizerYYsetInsidePre(TRUE);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Preformatted,tokenName);
parent->setInsidePreformatted(FALSE);
- doctokenizerYYsetInsidePre(FALSE);
+ //doctokenizerYYsetInsidePre(FALSE);
}
break;
case HTML_CODE:
@@ -2394,8 +2442,78 @@ int DocHtmlDescTitle::parse()
switch (tok)
{
case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <dt> tag",
- g_token->name.data());
+ {
+ QString cmdName=g_token->name;
+ bool isJavaLink=FALSE;
+ switch (CmdMapper::map(cmdName))
+ {
+ case CMD_REF:
+ {
+ int tok=doctokenizerYYlex();
+ if (tok!=TK_WHITESPACE)
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
+ g_token->name.data());
+ }
+ else
+ {
+ doctokenizerYYsetStateRef();
+ tok=doctokenizerYYlex(); // get the reference id
+ if (tok!=TK_WORD)
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
+ tokToString(tok),cmdName.data());
+ }
+ else
+ {
+ DocRef *ref = new DocRef(this,g_token->name);
+ m_children.append(ref);
+ ref->parse();
+ }
+ doctokenizerYYsetStatePara();
+ }
+ }
+ break;
+ case CMD_JAVALINK:
+ isJavaLink=TRUE;
+ // fall through
+ case CMD_LINK:
+ {
+ int tok=doctokenizerYYlex();
+ if (tok!=TK_WHITESPACE)
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
+ cmdName.data());
+ }
+ else
+ {
+ doctokenizerYYsetStateLink();
+ tok=doctokenizerYYlex();
+ if (tok!=TK_WORD)
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
+ tokToString(tok),cmdName.data());
+ }
+ else
+ {
+ doctokenizerYYsetStatePara();
+ DocLink *lnk = new DocLink(this,g_token->name);
+ m_children.append(lnk);
+ QString leftOver = lnk->parse(isJavaLink);
+ if (!leftOver.isEmpty())
+ {
+ m_children.append(new DocWord(this,leftOver));
+ }
+ }
+ }
+ }
+
+ break;
+ default:
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <dt> tag",
+ g_token->name.data());
+ }
+ }
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
@@ -2413,6 +2531,17 @@ int DocHtmlDescTitle::parse()
{
// ignore </dt> tag.
}
+ else if (tagId==HTML_DT)
+ {
+ // missing <dt> tag.
+ retval = RetVal_DescTitle;
+ goto endtitle;
+ }
+ else if (tagId==HTML_DL && g_token->endTag)
+ {
+ retval=RetVal_EndDesc;
+ goto endtitle;
+ }
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <dt> context",
@@ -2518,7 +2647,7 @@ int DocHtmlDescList::parse()
{
retval=dd->parse();
}
- else
+ else if (retval!=RetVal_DescTitle)
{
// error
break;
@@ -3630,7 +3759,7 @@ int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tag
case HTML_PRE:
handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
setInsidePreformatted(TRUE);
- doctokenizerYYsetInsidePre(TRUE);
+ //doctokenizerYYsetInsidePre(TRUE);
break;
case HTML_P:
retval=TK_NEWPARA;
@@ -3759,14 +3888,21 @@ int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tag
{
HtmlAttribListIterator li(tagHtmlAttribs);
HtmlAttrib *opt;
+ bool found=FALSE;
for (li.toFirst();(opt=li.current());++li)
{
+ //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
if (opt->name=="src" && !opt->value.isEmpty())
{
DocImage *img = new DocImage(this,opt->value,DocImage::Html);
m_children.append(img);
+ found = TRUE;
}
}
+ if (!found)
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: IMG tag does not have a SRC attribute!\n");
+ }
}
break;
case HTML_UNKNOWN:
@@ -3849,9 +3985,9 @@ int DocPara::handleHtmlEndTag(const QString &tagName)
handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
break;
case HTML_PRE:
- handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"preformatted");
+ handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
setInsidePreformatted(FALSE);
- doctokenizerYYsetInsidePre(FALSE);
+ //doctokenizerYYsetInsidePre(FALSE);
break;
case HTML_P:
// ignore </p> tag
@@ -3918,6 +4054,7 @@ int DocPara::parse()
{
DBG(("DocPara::parse() start\n"));
g_nodeStack.push(this);
+ handleInitialStyleCommands(this,m_children);
int tok;
int retval=0;
while ((tok=doctokenizerYYlex())) // get the next token
@@ -4369,6 +4506,8 @@ void DocText::parse()
}
}
+ handleUnclosedStyleCommands();
+
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
}
@@ -4423,6 +4562,8 @@ void DocRoot::parse()
retval = in->parse();
}
+ handleUnclosedStyleCommands();
+
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
}
@@ -4443,6 +4584,7 @@ DocNode *validatingParseDoc(const char *fileName,int startLine,
g_memberDef = md;
g_nodeStack.clear();
g_styleStack.clear();
+ g_initialStyleStack.clear();
g_inSeeBlock = FALSE;
g_insideHtmlLink = FALSE;
g_includeFileText = "";
@@ -4491,6 +4633,7 @@ DocNode *validatingParseText(const char *input)
g_memberDef = 0;
g_nodeStack.clear();
g_styleStack.clear();
+ g_initialStyleStack.clear();
g_inSeeBlock = FALSE;
g_insideHtmlLink = FALSE;
g_includeFileText = "";