BREAKING/REWORKED: Separated the LaTeX parser into JKQTMathTextLatexParser from JKQTMathText

This commit is contained in:
jkriege2 2022-08-20 16:19:40 +02:00
parent d4c024fcd8
commit 6273e469cd
17 changed files with 1814 additions and 1411 deletions

View File

@ -24,6 +24,13 @@
This group assembles general information around JKQTMathText. It explains the rendering model, lists the supported LaTeX-subset etc.
\defgroup jkqtmathtext_general_languages Supported Markup Languages
\ingroup jkqtmathtext_general
\defgroup jkqtmathtext_general_latex LaTeX Markup
\ingroup jkqtmathtext_general_languages
LaTeX is the default markup language and supported in JKQTMathText via JKQTMathTextLatexParser.
\defgroup jkqtmathtext_render Math Renderer Class (JKQTMathText)
\ingroup jkqtmathtext
@ -52,6 +59,9 @@
This group contains all classes that are used to build a memory-representation of the math to be rendered.
They form a tree in memory.
\defgroup jkqtmathtext_parser Math Markup Parser Classes
\ingroup jkqtmathtext
\defgroup jkqtmathtext_tools Tool Functions and Types for JKQTMathText
\ingroup jkqtmathtext_interaltools

View File

@ -1,7 +1,7 @@
/*!
\defgroup jkqtmathtext_supportedlatex Supported LaTeX-Subset
\ingroup jkqtmathtext_general
\ingroup jkqtmathtext_general_latex
\tableofcontents

View File

@ -1,6 +1,6 @@
/*!
\defgroup jkqtmathtext_supportedlatexsymbols Supported LaTeX-Symbols
\ingroup jkqtmathtext_general
\ingroup jkqtmathtext_general_latex
\tableofcontents

View File

@ -57,6 +57,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>IMPROVED/REWORKED rendering of text in text- and math-mode. Now it is more consistent with the output of LaTeX itself</li>
<li>IMPROVED/REWORKED rendering of blackboard font: now several different rendering modes can be selected using JKQTMathText::setFontBlackboradMode()</li>
<li>BREAKING/REWORKED: The \\verb!...!-command now works the same as in LaTeX</li>
<li>BREAKING/REWORKED: Separated the LaTeX parser into JKQTMathTextLatexParser from JKQTMathText</li>
<li>BREAKING/CLEANUP: cleanup: Removed Parameter prevNodeSize from JKQTMathTextNode::draw() and JKQTMathTextNode::getSize()/JKQTMathTextNode::getSizeInternal(), since it is only really necessary for JKQTMathTextSubscriptNode and JKQTMathTextSuperscriptNode</li>
<li>BREAKING/CLEANUP: using JKQTMathTextNodeSize for all size-calculation functions and got rid of all functions that take the output parameters with call-by-reference, additional information can be outut by local size-classes that derive from JKQTMathTextNodeSize, see e.g. JKQTMathTextSymbolNode::NodeSize and JKQTMathTextSymbolNode::getSymbolSize()</li>
<li>NEW: JKQTMathTextVerticalListNode allows to typeset a vertical list of lines</li>

View File

@ -685,7 +685,7 @@ void TestForm::updateMath()
double durationParse=0;
if (mt.parse(mathTest)) {
durationParse=ht.getTime()/1000.0;
ui->tree->addTopLevelItem(createTree(mt.getParsedNode()));
ui->tree->addTopLevelItem(createTree(mt.getNodeTree()));
} else {
durationParse=ht.getTime()/1000.0;
}

View File

@ -25,8 +25,10 @@ isEmpty(JKQTP_MATHTEXT_PRI_INCLUDED) {
$$PWD/jkqtmathtext/nodes/jkqtmathtextnodetools.h \
$$PWD/jkqtmathtext/nodes/jkqtmathtextnoopnode.h \
$$PWD/jkqtmathtext/nodes/jkqtmathtextverbatimnode.h \
$$PWD/jkqtmathtext/nodes/jkqtmathtextboxinstructionnode.cpp \
$$PWD/jkqtmathtext/nodes/jkqtmathtextmodifyenvironmentnode.cpp
$$PWD/jkqtmathtext/nodes/jkqtmathtextboxinstructionnode.h \
$$PWD/jkqtmathtext/nodes/jkqtmathtextmodifyenvironmentnode.h \
$$PWD/jkqtmathtext/parsers/jkqtmathtextparser.h \
$$PWD/jkqtmathtext/parsers/jkqtmathtextlatexparser.h
SOURCES += $$PWD/jkqtmathtext/jkqtmathtext.cpp \
@ -49,7 +51,9 @@ isEmpty(JKQTP_MATHTEXT_PRI_INCLUDED) {
$$PWD/jkqtmathtext/nodes/jkqtmathtextnoopnode.cpp \
$$PWD/jkqtmathtext/nodes/jkqtmathtextverbatimnode.cpp \
$$PWD/jkqtmathtext/nodes/jkqtmathtextboxinstructionnode.cpp \
$$PWD/jkqtmathtext/nodes/jkqtmathtextmodifyenvironmentnode.cpp
$$PWD/jkqtmathtext/nodes/jkqtmathtextmodifyenvironmentnode.cpp\
$$PWD/jkqtmathtext/parsers/jkqtmathtextparser.cpp \
$$PWD/jkqtmathtext/parsers/jkqtmathtextlatexparser.cpp
include($$PWD/jkqtmathtext/resources/xits.pri)
DEFINES += AUTOLOAD_XITS_FONTS

View File

@ -46,6 +46,11 @@ set(SOURCES_NODES
${CMAKE_CURRENT_LIST_DIR}/nodes/jkqtmathtextverbatimnode.cpp
)
set(SOURCES_PARSERS
${CMAKE_CURRENT_LIST_DIR}/parsers/jkqtmathtextparser.cpp
${CMAKE_CURRENT_LIST_DIR}/parsers/jkqtmathtextlatexparser.cpp
)
set(HEADERS
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/jkqtmathtext.h>
$<INSTALL_INTERFACE:jkqtmathtext.h>
@ -56,6 +61,7 @@ set(HEADERS
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/jkqtmathtext_imexport.h>
$<INSTALL_INTERFACE:jkqtmathtext_imexport.h>
)
set(HEADERS_NODES
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/nodes/jkqtmathtextnode.h>
$<INSTALL_INTERFACE:nodes/jkqtmathtextnode.h>
@ -97,6 +103,14 @@ set(HEADERS_NODES
$<INSTALL_INTERFACE:nodes/jkqtmathtextverbatimnode.h>
)
set(HEADERS_PARSERS
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/parsers/jkqtmathtextparser.h>
$<INSTALL_INTERFACE:parsers/jkqtmathtextparser.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/parsers/jkqtmathtextlatexparser.h>
$<INSTALL_INTERFACE:parsers/jkqtmathtextlatexparser.h>
)
if(JKQtPlotter_BUILD_INCLUDE_XITS_FONTS)
set(RESOURCES
${CMAKE_CURRENT_LIST_DIR}/resources/xits.qrc
@ -136,7 +150,7 @@ function(JKQtMathText_setDefaultLibOptions TARGETNAME)
endfunction()
if(JKQtPlotter_BUILD_SHARED_LIBS)
add_library(${libsh_name} SHARED ${SOURCES} ${RESOURCES} ${HEADERS} ${SOURCES_NODES} ${HEADERS_NODES} )
add_library(${libsh_name} SHARED ${SOURCES} ${RESOURCES} ${HEADERS} ${SOURCES_NODES} ${HEADERS_NODES} ${SOURCES_PARSERS} ${HEADERS_PARSERS})
JKQtMathText_setDefaultLibOptions(${libsh_name})
set_property(TARGET ${libsh_name} PROPERTY OUTPUT_NAME "${libsh_name_decorated}")
target_link_libraries(${libsh_name} PUBLIC JKQTCommonSharedLib)
@ -149,7 +163,7 @@ if(JKQtPlotter_BUILD_SHARED_LIBS)
endif()
if(JKQtPlotter_BUILD_STATIC_LIBS)
add_library(${lib_name} STATIC ${SOURCES} ${RESOURCES} ${HEADERS} ${SOURCES_NODES} ${HEADERS_NODES})
add_library(${lib_name} STATIC ${SOURCES} ${RESOURCES} ${HEADERS} ${SOURCES_NODES} ${HEADERS_NODES} ${SOURCES_PARSERS} ${HEADERS_PARSERS})
JKQtMathText_setDefaultLibOptions(${lib_name})
set_property(TARGET ${lib_name} PROPERTY OUTPUT_NAME "${lib_name_decorated}")

File diff suppressed because it is too large Load Diff

View File

@ -34,34 +34,48 @@
#include <QFile>
#include "jkqtmathtext/jkqtmathtext_imexport.h"
#include "jkqtmathtext/jkqtmathtexttools.h"
#include <QWidget>
#include <QLabel>
#include <QHash>
#include <QPicture>
#include <QImage>
#include <QPixmap>
#include <type_traits>
class JKQTMathTextNode; // forward
class JKQTMathTextParser; // forward
class JKQTMathTextVerticalListNode; // forward
/*! \brief this class parses a LaTeX string and can then draw the contained text/equation onto a <a href="http://doc.qt.io/qt-5/qpainter.html">QPainter</a>
/*! \brief this class parses a mathematical markup string and can then draw the contained text/equation onto a <a href="http://doc.qt.io/qt-5/qpainter.html">QPainter</a>
\ingroup jkqtmathtext_render
JKQTMathText is a self-contained LaTeX-renderer for Qt. It is used to renderer
JKQTMathText is a self-contained mathematical markup renderer for Qt. It is used to renderer
labels in JKQTPlotter/JKQTBasePlotter, but can be used independently.
The class does not depend on any library, except Qt.
In particular it actually parses a LaTeX string and draws it in pure C++. It does NOT rely
The implementation is split over several classes:
- JKQTMathText implements drawing, based on a memory representatioj of the markup. It also provides an interface for class users.
- JKQTMathTextParser and its children like JKQTMathTextLatexParser parses mathamtical markup.
- The nodes summarized in \ref jkqtmathtext_nodes are used to build the memory representation of the markup.
.
In particular JKQTMathTextLatexParser actually parses e.g. a LaTeX string and draws it in pure C++. It does NOT rely
on an installed LaTeX for the rendering!
\see See \ref jkqtmathtext_supportedlatex for a description of the supported LaTeX subset
and \ref jkqtmathtext_renderingmodel for a description of the rendering model.
and \ref jkqtmathtext_renderingmodel for a description of the rendering model of JKQTMathTextLatexParser.
\section JKQTMathTextUsage Usage
\subsection JKQTMathTextUsageParsing Parsing Functions
The class provieds two flavours of a parsing function:
- There is a function \c parse(markup, markupType) that accepts the markup, the type of markup (as enum DefaultParserTypes) and parser options.
This function determines the appropriate parser class, based on the markup type.
- A templated function parse<TParser>(markup, options) that gets a parser class to be used on the markup.
.
\subsection JKQTMathTextUsageDirect Drawing Functions
The class provides different variants of the drawing function draw() that paints using an
externlly provided <a href="https://doc.qt.io/qt-6/qpainter.html">QPainter</a>. These variants
@ -72,6 +86,8 @@ class JKQTMathTextVerticalListNode; // forward
\image html jkqtmathtext/jkqtmathtext_node_geo.png
Note that you first need to call one of the \ref JKQTMathTextUsageParsing so there is anything to render!
\subsection JKQTMathTextUsageConvenience Convenience Functions
@ -203,6 +219,9 @@ class JKQTMathTextVerticalListNode; // forward
class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
Q_OBJECT
public:
friend class JKQTMathTextParser;
friend class JKQTMathTextNode;
/** \brief minimum linewidth allowed in a JKQTMathText (given in pt) */
static const double ABS_MIN_LINEWIDTH;
@ -224,14 +243,42 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
};
Q_DECLARE_FLAGS(ParseOptions, ParseOption)
Q_FLAG(ParseOptions)
/** \brief parse the given LaTeX string.
/** \brief lists the parser classes that are available by default (convenience interface to the templated parse()-funktion */
enum DefaultParserTypes {
LatexParser, /*!< \brief use the LaTeX parser from JKQTMathTextLatexParser */
DefaultParser=LatexParser
};
/** \brief parse the given math \a markup string with a parser derived from \a markuptType.
*
* \param markup the string of math markup
* \param markupType defines the language the \a markup is written in (and is used to derive the parser to use)
* \param options Options for parsing, \see ParseOptions
* \param allowLinebreaks
*
* \returns \c true on success.
*/
bool parse(const QString &text, ParseOptions options=DefaultParseOptions);
bool parse(const QString &markup, DefaultParserTypes markuptType=DefaultParser, ParseOptions options=DefaultParseOptions);
/** \brief parse the given math \a markup string, using the given parser class \a TParser
*
* \tparam TParser the parser (deived from JKQTMathTextParser) to be used
* \param markup the string of math markup
* \param options Options for parsing, \see ParseOptions
*
* \returns \c true on success.
*/
template <class TParser>
inline bool parse(const QString &markup, ParseOptions options=DefaultParseOptions) {
static_assert(std::is_base_of<JKQTMathTextParser, TParser>::value, "in parse<TParser>() the type TParser has to be derived from JKQTMathTextParser to work!");
std::unique_ptr<TParser> p=std::make_unique<TParser>(this);
if (parsedNode) delete parsedNode;
parsedNode=nullptr;
clearErrorList();
parsedNode=p->parse(markup, options);
return parsedNode!=nullptr;
}
/** \brief returns the syntax tree of JKQTMathTextNode's that was created by the last parse() call */
JKQTMathTextNode* getNodeTree() ;
/** \copydoc parsedNode */
const JKQTMathTextNode *getNodeTree() const;
/** \brief get the size of the drawn representation. returns an invalid size if no text has been parsed. */
QSizeF getSize(QPainter& painter);
@ -652,12 +699,15 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
QStringList getErrorList() const;
/** \brief returns \c true when errors were registered in the system \see error_list */
bool hadErrors() const;
protected:
/** \copydoc error_list */
void addToErrorList(const QString& error);
/** \brief clears all registered errors (see error_list)
*/
void clearErrorList();
protected:
/** \brief table with font replacements to use (e.g. if it is known that a certain font is not good for rendering, you can add
* an alternative using addReplacementFont(). These are automatically applied, when setting a new font name! */
QMap<QString, QString> fontReplacements;
@ -885,114 +935,10 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
*/
QStringList error_list;
/** \brief the result of parsing the last string supplied to the object via parse() */
/** \brief the syntax tree of JKQTMathTextNode's that was created by the last parse() call */
JKQTMathTextNode* parsedNode;
/** \brief returns the syntax tree of JKQTMathTextNode's that was created by the last parse call */
JKQTMathTextNode* getNodeTree() const;
/** \brief the token types that may arrise in the string */
enum tokenType {
MTTnone, /*!< \brief no token */
MTTtext, /*!< \brief a piece of general text */
MTTinstruction, /*!< \brief an instruction, started by \c "\", e.g. \c "\\textbf", ... */
MTTinstructionNewline, /*!< \brief a newline instruction \c "\\" */
MTTinstructionVerbatim, /*!< \brief a verbatim instruction, e.g. \c \\verb!verbatimtext! was found: currentTokenName will contain the text enclode by the verbatim delimiters */
MTTinstructionVerbatimVisibleSpace, /*!< \brief a verbatim instruction that generates visible whitespaces, e.g. \c \\begin{verbatim}...\\end{verbatim} was found: currentTokenName will contain the text enclode by the verbatim delimiters */
MTTinstructionBegin, /*!< \brief a \c '\\begin{...}' instruction, currentTokenName is the name of the environment */
MTTinstructionEnd, /*!< \brief a \c '\\end{...}' instruction, currentTokenName is the name of the environment */
MTTunderscore, /*!< \brief the character \c "_" */
MTThat, /*!< \brief the character \c "^" */
MTTdollar, /*!< \brief the character \c "$" */
MTTopenbrace, /*!< \brief the character \c "{" */
MTTclosebrace, /*!< \brief the character \c "}" */
MTTopenbracket, /*!< \brief the character \c "[" */
MTTclosebracket, /*!< \brief the character \c "]" */
MTTwhitespace, /*!< \brief some whitespace */
MTTampersand, /*!< \brief the character \c "&" */
MTThyphen, /*!< \brief the single hyphen character \c "-" in text-mode \note MTTendash and MTTemdash take precedence over MTThypen */
MTTendash, /*!< \brief the en-dash character sequence \c "--" in text-mode */
MTTemdash, /*!< \brief the em-dash character sequence \c "---" in text-mode */
};
/** \brief convert a tokenType into a string, e.g. for debugging output */
static QString tokenType2String(tokenType type);
/** \brief tokenizer for the LaTeX parser */
tokenType getToken();
/** \brief returns some characters to the Tokenizer */
void giveBackToTokenizer(size_t count);
/** \brief parse a LaTeX string
*
* \param get if \c true this calls getToken()
* \param quitOnClosingBrace if unequal MTBTAny, this returns if the given closing brace is found
* \param quitOnEnvironmentEnd wuit if \c \\end{quitOnEnvironmentEnd} is found
* \param quitOnClosingBracket if \c true, quits on encountering a MTTclosebracket token
*/
JKQTMathTextNode* parseLatexString(bool get, JKQTMathTextBraceType quitOnClosingBrace=JKQTMathTextBraceType::MTBTAny, const QString& quitOnEnvironmentEnd=QString(""), bool quitOnClosingBracket=false);
/** \brief parse a LaTeX string with linebreaks
*
* \param get if \c true this calls getToken()
* \param quitOnEnvironmentEnd wuit if \c \\end{quitOnEnvironmentEnd} is found
* \param _alignment horizontal alignment of the JKQTMathTextVerticalListNode \see JKQTMathTextVerticalListNode::alignment and JKQTMathTextHorizontalAlignment
* \param _linespacingFactor line spacing factor of the lines \see JKQTMathTextVerticalListNode::linespacingFactor
* \param spacingMode_ spacing mode/algorithm for the lines \see JKQTMathTextLineSpacingMode and JKQTMathTextLineSpacingMode
* \param _verticalOrientation vertical orientation of the block of all lines, see JKQTMathTextVerticalListNode::verticalOrientation and JKQTMathTextVerticalOrientation
*
* \returns JKQTMathTextVerticalListNode with the lines as children
*/
JKQTMathTextVerticalListNode *parseMultilineLatexString(bool get, const QString& quitOnEnvironmentEnd=QString(""), JKQTMathTextHorizontalAlignment _alignment=MTHALeft, double _linespacingFactor=1.0, JKQTMathTextLineSpacingMode spacingMode_=MTSMDefaultSpacing, JKQTMathTextVerticalOrientation _verticalOrientation=MTVOFirstLine);
/** \brief parses a list of string-arguments, i.e. \c {p1}{p2}{...}
*
* \param get call getToken() at the start, otherwise it is expected that currentToken==MTTopenbrace
* \param Nparams the number of parameters to expect
* \param[out] foundError will be set to \c true if an error occured (unexpected token) or \c false otherwise
* \return the list of parameter strings with Nparam entries or an empty or partial list on error
*/
QStringList parseStringParams(bool get, size_t Nparams, bool *foundError=nullptr);
/** \brief parses a string, i.e. a sequence of text and whitespaces. returns after any other token was found */
QString parseSingleString(bool get);
/** \brief read all text without tokenizing, until the sequence \a endsequence is found.
*
* \param get if \c true the functions begins by reading a new character, otherwise the current character is used as first character
* \param endsequence the sequence, ending the read
* \param removeFirstlineWhitespace if \c true the returned string does not contain the first whitespace-line and a possible trailing whitespace line
* \return the read string, excluding the \a endsequence
*/
QString readUntil(bool get, const QString& endsequence, bool removeFirstlineWhitespace=false);
/** \brief parses a single instruction (including it's parameters)
*
* \param[out] _foundError will be set to \c true if an error occured (unexpected token) or \c false otherwise
* \param[out] getNew returns \c true if the parser has to call getToken() to go on
* \return the instruction node or \c nullptr on error (then also \a _foundError is set \c true )
* \note This method expects the current token currentToken to be MTTinstruction
*/
JKQTMathTextNode* parseInstruction(bool *_foundError=nullptr, bool* getNew=nullptr);
/** \brief parse a LaTeX math environment */
JKQTMathTextNode* parseMath(bool get);
/** \brief used by the tokenizer. type of the current token */
tokenType currentToken;
/** \brief the JKQTMathTextBraceType associated with the last \c \\right command the parser encountered */
JKQTMathTextBraceType lastRightBraceType;
/** \brief returns the number of \c \\hline , \c \\hdashline , ... commands in the last parseLatexString() call */
QMap<QString,size_t> lastLineCount;
/** \brief used by the tokenizer. Name of the current token, id applicable */
QString currentTokenName;
/** \brief used by the tokenizer. Points to the currently read character in parseString */
int currentTokenID;
/** \brief used by the tokenizer. The string to be parsed */
QString parseString;
/** \brief used by the parser. indicates whether we are in a math environment */
bool parsingMathEnvironment;
/** \brief used by the parser. indicates whether to use textstyle or displaystyle in math-mode */
bool parsinginMathTextStyle;
public:
/** \copydoc parsedNode */
JKQTMathTextNode *getParsedNode() const;
};

View File

@ -297,7 +297,7 @@ void JKQTMathTextMatrixNode::parseColumnSpec(const QString &columnSpec)
verticalLineRHSColumn[columnAlignment.size()-1]=LTdashed;
}
} else if (!columnSpec[i].isSpace()){
parentMathText->addToErrorList(QString("array spec has unknown character '%1' (full spec was '%2')").arg(columnSpec[i]).arg(columnSpec));
addToErrorList(QString("array spec has unknown character '%1' (full spec was '%2')").arg(columnSpec[i]).arg(columnSpec));
}
i++;
}

View File

@ -114,6 +114,11 @@ void JKQTMathTextNode::doDrawBoxes(QPainter& painter, double x, double y, JKQTMa
}
}
void JKQTMathTextNode::addToErrorList(const QString &error)
{
parentMathText->addToErrorList(error);
}
void JKQTMathTextNode::setDrawBoxes(bool draw)
{
this->drawBoxes=draw;

View File

@ -160,6 +160,13 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextNode {
}
return lst;
}
/** \brief adds a new error to the JKQTMathText referenced by parentMathText
*
* \see JKQTMathText::addToErrorList()
*/
void addToErrorList(const QString& error);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,204 @@
/*
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
with contributions from: Razi Alavizadeh
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTMATHTEXTLATEXPARSER_H
#define JKQTMATHTEXTLATEXPARSER_H
#include "jkqtmathtext/parsers/jkqtmathtextparser.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include "jkqtmathtext/jkqtmathtext_imexport.h"
#include <QHash>
#include <QSet>
#include <QMap>
#include <QString>
class JKQTMathTextNode; // forward
class JKQTMathTextVerticalListNode; // forward
/*! \brief a LaTeX parser for JKQTMathText
\ingroup jkqtmathtext_parser
JKQTMathText is a self-contained mathematical markup renderer for Qt. It is used to renderer
labels in JKQTPlotter/JKQTBasePlotter, but can be used independently.
That class is responsible for rendering a memory representation of mathematical markup,
but relies on the current class JKQTMathTextLatexParser to parse a LaTeX string into
the mentioned memory representation.
\see See \ref jkqtmathtext_supportedlatex for a description of the supported LaTeX subset
and \ref jkqtmathtext_renderingmodel for a description of the rendering model.
In particular JKQTMathTextLatexParser actually parses e.g. a LaTeX string and draws it in pure C++. It does NOT rely
on an installed LaTeX for the rendering!
*/
class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextLatexParser : public JKQTMathTextParser {
Q_OBJECT
public:
/** \brief class constructor */
JKQTMathTextLatexParser(JKQTMathText * parent = nullptr);
/** \brief class destructor */
~JKQTMathTextLatexParser();
virtual JKQTMathTextNode* parse(const QString &text, JKQTMathText::ParseOptions options=JKQTMathText::DefaultParseOptions) override;
protected:
/** \brief the token types that may arrise in the string */
enum tokenType {
MTTnone, /*!< \brief no token */
MTTtext, /*!< \brief a piece of general text */
MTTinstruction, /*!< \brief an instruction, started by \c "\", e.g. \c "\\textbf", ... */
MTTinstructionNewline, /*!< \brief a newline instruction \c "\\" */
MTTinstructionVerbatim, /*!< \brief a verbatim instruction, e.g. \c \\verb!verbatimtext! was found: currentTokenName will contain the text enclode by the verbatim delimiters */
MTTinstructionVerbatimVisibleSpace, /*!< \brief a verbatim instruction that generates visible whitespaces, e.g. \c \\begin{verbatim}...\\end{verbatim} was found: currentTokenName will contain the text enclode by the verbatim delimiters */
MTTinstructionBegin, /*!< \brief a \c '\\begin{...}' instruction, currentTokenName is the name of the environment */
MTTinstructionEnd, /*!< \brief a \c '\\end{...}' instruction, currentTokenName is the name of the environment */
MTTunderscore, /*!< \brief the character \c "_" */
MTThat, /*!< \brief the character \c "^" */
MTTdollar, /*!< \brief the character \c "$" */
MTTopenbrace, /*!< \brief the character \c "{" */
MTTclosebrace, /*!< \brief the character \c "}" */
MTTopenbracket, /*!< \brief the character \c "[" */
MTTclosebracket, /*!< \brief the character \c "]" */
MTTwhitespace, /*!< \brief some whitespace */
MTTampersand, /*!< \brief the character \c "&" */
MTThyphen, /*!< \brief the single hyphen character \c "-" in text-mode \note MTTendash and MTTemdash take precedence over MTThypen */
MTTendash, /*!< \brief the en-dash character sequence \c "--" in text-mode */
MTTemdash, /*!< \brief the em-dash character sequence \c "---" in text-mode */
};
/** \brief convert a tokenType into a string, e.g. for debugging output */
static QString tokenType2String(tokenType type);
/** \brief tokenizer for the LaTeX parser */
tokenType getToken();
/** \brief returns some characters to the Tokenizer */
void giveBackToTokenizer(size_t count);
/** \brief parse a LaTeX string
*
* \param get if \c true this calls getToken()
* \param quitOnClosingBrace if unequal MTBTAny, this returns if the given closing brace is found
* \param quitOnEnvironmentEnd wuit if \c \\end{quitOnEnvironmentEnd} is found
* \param quitOnClosingBracket if \c true, quits on encountering a MTTclosebracket token
*/
JKQTMathTextNode* parseLatexString(bool get, JKQTMathTextBraceType quitOnClosingBrace=JKQTMathTextBraceType::MTBTAny, const QString& quitOnEnvironmentEnd=QString(""), bool quitOnClosingBracket=false);
/** \brief parse a LaTeX string with linebreaks
*
* \param get if \c true this calls getToken()
* \param quitOnEnvironmentEnd wuit if \c \\end{quitOnEnvironmentEnd} is found
* \param _alignment horizontal alignment of the JKQTMathTextVerticalListNode \see JKQTMathTextVerticalListNode::alignment and JKQTMathTextHorizontalAlignment
* \param _linespacingFactor line spacing factor of the lines \see JKQTMathTextVerticalListNode::linespacingFactor
* \param spacingMode_ spacing mode/algorithm for the lines \see JKQTMathTextLineSpacingMode and JKQTMathTextLineSpacingMode
* \param _verticalOrientation vertical orientation of the block of all lines, see JKQTMathTextVerticalListNode::verticalOrientation and JKQTMathTextVerticalOrientation
*
* \returns JKQTMathTextVerticalListNode with the lines as children
*/
JKQTMathTextVerticalListNode *parseMultilineLatexString(bool get, const QString& quitOnEnvironmentEnd=QString(""), JKQTMathTextHorizontalAlignment _alignment=MTHALeft, double _linespacingFactor=1.0, JKQTMathTextLineSpacingMode spacingMode_=MTSMDefaultSpacing, JKQTMathTextVerticalOrientation _verticalOrientation=MTVOFirstLine);
/** \brief parses a list of string-arguments, i.e. \c {p1}{p2}{...}
*
* \param get call getToken() at the start, otherwise it is expected that currentToken==MTTopenbrace
* \param Nparams the number of parameters to expect
* \param[out] foundError will be set to \c true if an error occured (unexpected token) or \c false otherwise
* \return the list of parameter strings with Nparam entries or an empty or partial list on error
*/
QStringList parseStringParams(bool get, size_t Nparams, bool *foundError=nullptr);
/** \brief parses a string, i.e. a sequence of text and whitespaces. returns after any other token was found */
QString parseSingleString(bool get);
/** \brief read all text without tokenizing, until the sequence \a endsequence is found.
*
* \param get if \c true the functions begins by reading a new character, otherwise the current character is used as first character
* \param endsequence the sequence, ending the read
* \param removeFirstlineWhitespace if \c true the returned string does not contain the first whitespace-line and a possible trailing whitespace line
* \return the read string, excluding the \a endsequence
*/
QString readUntil(bool get, const QString& endsequence, bool removeFirstlineWhitespace=false);
/** \brief parses a single instruction (including it's parameters)
*
* \param[out] _foundError will be set to \c true if an error occured (unexpected token) or \c false otherwise
* \param[out] getNew returns \c true if the parser has to call getToken() to go on
* \return the instruction node or \c nullptr on error (then also \a _foundError is set \c true )
* \note This method expects the current token currentToken to be MTTinstruction
*/
JKQTMathTextNode* parseInstruction(bool *_foundError=nullptr, bool* getNew=nullptr);
/** \brief parse a LaTeX math environment */
JKQTMathTextNode* parseMath(bool get);
/** \brief used by the tokenizer. type of the current token */
tokenType currentToken;
/** \brief the JKQTMathTextBraceType associated with the last \c \\right command the parser encountered */
JKQTMathTextBraceType lastRightBraceType;
/** \brief returns the number of \c \\hline , \c \\hdashline , ... commands in the last parseLatexString() call */
QMap<QString,size_t> lastMatrixLineCommandCount;
/** \brief used by the tokenizer. Name of the current token, id applicable */
QString currentTokenName;
/** \brief used by the tokenizer. Points to the currently read character in parseString */
int currentTokenID;
/** \brief used by the tokenizer. The string to be parsed */
QString parseString;
/** \brief used by the parser. indicates whether we are in a math environment */
bool parsingMathEnvironment;
/** \brief used by the parser. indicates whether to use textstyle or displaystyle in math-mode */
bool parsinginMathTextStyle;
/** \brief characters that initiate a new token */
static QSet<QChar> TokenCharacters;
/** \brief characters that require special treatment in math mode */
static QSet<QChar> mathEnvironmentSpecialChars;
/** \brief characters that require special treatment in math mode */
static QSet<QChar> mathEnvironmentSpecialEndChars;
/** \brief single character instructions */
static QSet<QChar> SingleCharInstructions;
/** \brief maps instructions for accents in text-mode (e.g. \c \\'a or \c \\ae ) to the corresponding unicode character */
static QHash<QString, QChar> accentLetters;
/** \brief lists all lengths of keys in accentLetters that start with a backslash */
static QSet<int> accentLetters_LenBackslash;
/** \brief lists all lengths of keys in accentLetters that start with a curly brace */
static QSet<int> accentLetters_LenCurly;
/** \brief characters that have to be replaced by the correspcoting JKQTMathTextSymbolNode in math mode */
static QSet<QString> mathEnvironmentSpecialText;
/** \brief maps instructions for braces with fixed size, e.g \c \\bigl to the magnification factor of the brace versus the base font */
static QHash<QString,double> big_instructions_family;
/** \brief fills all static data structures, if they are still empty */
static void initStaticStructures();
};
#endif // JKQTMATHTEXTLATEXPARSER_H

View File

@ -0,0 +1,52 @@
/*
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "jkqtmathtext/parsers/jkqtmathtextparser.h"
#include "jkqtmathtext/jkqtmathtext.h"
JKQTMathTextParser::JKQTMathTextParser(JKQTMathText* parent):
QObject(parent), parentMathText(parent)
{
}
JKQTMathTextParser::~JKQTMathTextParser() {
}
JKQTMathText *JKQTMathTextParser::getParentMathText()
{
return parentMathText;
}
const JKQTMathText *JKQTMathTextParser::getParentMathText() const
{
return parentMathText;
}
void JKQTMathTextParser::addToErrorList(const QString &error)
{
parentMathText->addToErrorList(error);
}
void JKQTMathTextParser::clearErrorList()
{
parentMathText->clearErrorList();
}

View File

@ -0,0 +1,87 @@
/*
Copyright (c) 2008-2022 Jan W. Krieger (<jan@jkrieger.de>)
with contributions from: Razi Alavizadeh
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License (LGPL) as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License (LGPL) for more details.
You should have received a copy of the GNU Lesser General Public License (LGPL)
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JKQTMATHTEXTPARSER_H
#define JKQTMATHTEXTPARSER_H
#include "jkqtmathtext/jkqtmathtext_imexport.h"
#include "jkqtmathtext/jkqtmathtext.h"
#include <QFlags>
#include <QObject>
#include <QString>
class JKQTMathTextNode; // forward
/*! \brief base class for all parsers used by JKQTMathText
\ingroup jkqtmathtext_parser
*/
class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextParser : public QObject {
Q_OBJECT
public:
/** \brief class constructor */
JKQTMathTextParser(JKQTMathText * parent = nullptr);
/** \brief class destructor */
virtual ~JKQTMathTextParser();
/** \brief parse the given mathematical markup string.
*
* \param text the markup to be parsed
* \param options Options for parsing, \see ParseOptions
*
* \returns the memory representation of the markup \c nullptr on failure.
*/
virtual JKQTMathTextNode* parse(const QString &text, JKQTMathText::ParseOptions options=JKQTMathText::DefaultParseOptions)=0;
/** \brief parentMathText */
JKQTMathText* getParentMathText();
/** \brief parentMathText */
const JKQTMathText* getParentMathText() const;
protected:
/** \brief JKQTMathText that instanciated and uses this parser */
JKQTMathText* parentMathText;
/** \brief adds a new error to the JKQTMathText referenced by parentMathText
*
* \see JKQTMathText::addToErrorList()
*/
void addToErrorList(const QString& error);
/** \brief clears the error list in the JKQTMathText referenced by parentMathText
*
* \see JKQTMathText::clearErrorList()
*/
void clearErrorList();
};
#endif // JKQTMATHTEXTPARSER_H

View File

@ -136,7 +136,7 @@ int main(int argc, char* argv[])
int i=1;
fileList<<"/*!\n"
" \\defgroup jkqtmathtext_supportedlatexsymbols Supported LaTeX-Symbols\n"
" \\ingroup jkqtmathtext_general\n\n\\tableofcontents\n\n";
" \\ingroup jkqtmathtext_general_latex\n\n\\tableofcontents\n\n";
fileList<<" \\section jkqtmathtext_supportedlatexsymbols_greek Greek Letters\n";
fileList<<" The following table lists all greek letters and their variants available in JKQTMathParser. They are defined in the node-class JKQTMathTextSymbolNode:\n";
fileList<<" <table>\n";
@ -512,7 +512,7 @@ int main(int argc, char* argv[])
<<"-----------------------------------------------------------\n"
<<mathText.getErrorList().join("\n").toStdString()<<"\n"
<<"-----------------------------------------------------------\n"
<<"RENDERTREE:\n"<<JKQTMathTextNodeTree2String(mathText.getParsedNode()).toStdString()
<<"RENDERTREE:\n"<<JKQTMathTextNodeTree2String(mathText.getNodeTree()).toStdString()
<<"-----------------------------------------------------------\n"
;
} else if (verbose) {
@ -521,7 +521,7 @@ int main(int argc, char* argv[])
<<"-----------------------------------------------------------\n"
<<latex[i].toStdString()<<"\n"
<<"-----------------------------------------------------------\n"
<<"RENDERTREE:\n"<<JKQTMathTextNodeTree2String(mathText.getParsedNode()).toStdString()
<<"RENDERTREE:\n"<<JKQTMathTextNodeTree2String(mathText.getNodeTree()).toStdString()
<<"-----------------------------------------------------------\n";
}