Qt Q_ENUM property from QVariant(qulonglong). - qt

Consider the following Qt code:
class Foo : public QObject {
Q_OBJECT
Q_ENUMS(E)
Q_PROPERTY(E x READ x WRITE set_x)
public:
enum E {
a = 0,
b = 1,
c = 2
};
E x() const { return x_; }
void set_x(E value) { x_ = value; }
private:
E x_;
};
int main (int argc, char **argv) {
QCoreApplication app(argc, argv);
Foo f;
f.setProperty("x", Foo::c);
std::cout << f.property("x").toInt() << std::endl; // 2
f.setProperty("x", QVariant((int)1));
std::cout << f.property("x").toInt() << std::endl; // 1
f.setProperty("x", QVariant((long long)0));
std::cout << f.property("x").toInt() << std::endl; // should be 0. is 1.
}
Why does it work that way?

If you test the return value of setProperty, you will see that the set is failing:
ok = f.setProperty("x", QVariant((long long)0));
std::cout << ok << std::endl; // 0, i.e. false
The relevant part of the Qt code is in qmetaobject.cpp, annotated below:
if (isEnumType()) {
if (v.type() == QVariant::String) {
// ... we won't get here.
} else if (v.type() != QVariant::Int && v.type() != QVariant::UInt) {
// We got here because we didn't provide an int or uint.
// This will be 0...
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
// ... which means this will return false; the property will not be set.
if ((enumMetaTypeId == 0) ||
(v.userType() != enumMetaTypeId) ||
!v.constData())
return false;
// ... we never get here
}
}
// ... we never get here
So the behavior seems to be by design: enum properties can only be set using QVariant objects with a type of int or uint.

Related

Why do I get false when I try to insert a record to a QSqlTableModel in QT?

I'm creating a QSqlRecord object and then I set the values to that QSqlRecord object. But even if I insert the QSqlRecord object to the QSqlTableModel object, the function of inserting records, returns false.
I have this C++ code and it create a QSqlRecord object and set the values. It setting the values in the correct indexed order as how the table was created.
/* Insert data */
int column_index = 0; /* Index 0 is the ID column */
QSqlRecord record;
qDebug() << CALIBRATION_COLUMNS.at(column_index).first;
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, 1); /* ID */
qDebug() << CALIBRATION_COLUMNS.at(column_index).first;
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, calibration_id);
qDebug() << CALIBRATION_COLUMNS.at(column_index).first;
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, calibration_comment);
qDebug() << CALIBRATION_COLUMNS.at(column_index).first;
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, calibration_date_time);
for(int i = 0; i < 12; i++){
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, min_adc[i]);
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, max_adc[i]);
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, bias_adc[i]);
}
for(int i = 0; i < 5; i++){
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, min_dadc[i]);
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, max_dadc[i]);
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, bias_dadc[i]);
}
for(int i = 0; i < 2; i++)
record.setValue(CALIBRATION_COLUMNS.at(column_index++).first, pulses_per_revolution_encoder[i]);
/* -1 means append record */
qDebug() << calibration_model->insertRecord(-1, record);
qDebug() << calibration_model->lastError().text();
qDebug() << "Submit:";
if(!calibration_model->submitAll()){
qDebug() << calibration_model->lastError().text();
return DATABASE_STATUS_COULD_NOT_INSERT_ROW;
}
return DATABASE_STATUS_OK;
But even if I insert the record, this function calibration_model->insertRecord(-1, record); returns false but the calibration_model->submitAll() returns true.
Output:
"ID"
"calibration_id"
"calibration_comment"
"calibration_date_time"
false
"No Fields to update"
Submit:
So tell me. What I'm I doing wrong here?
I'm getting the error No Fields to update, but what does that mean? I have an empty table and I just want to append with one row.
Not sure why you're getting that error. I have a small example for QSqlTableModel. Let me put it here. Maybe you could compare with your code.
main.cpp
#include <QApplication>
#include "mysqltablemodel.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("mydb");
if(!db.open()) {
qDebug() << db.lastError().text();
return 0;
}
QSqlQuery query(db);
if(!query.exec("DROP TABLE IF EXISTS mytable")) {
qDebug() << "create table error: " << query.lastError().text();
return 0;
}
if(!query.exec("CREATE TABLE IF NOT EXISTS mytable \
(id integer primary key autoincrement, name varchar(15), salary integer)")) {
qDebug() << "create table error: " << query.lastError().text();
return 0;
}
MySqlTableModel *model = new MySqlTableModel(0, db);
model->setTable("mytable");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();
QSqlRecord rec = model->record();
rec.setValue(1, "peter");
rec.setValue(2, 100);
qDebug() << model->insertRecord(-1, rec);
rec.setValue(1, "luke");
rec.setValue(2, 200);
qDebug() << model->insertRecord(-1, rec);
if(model->submitAll()) {
model->database().commit();
} else {
model->database().rollback();
qDebug() << "database error: " << model->lastError().text();
}
query.exec("SELECT name, salary FROM mytable");
while (query.next()){
QString name = query.value(0).toString();
int salary = query.value(1).toInt();
qDebug() << name << salary;
}
return app.exec();
}
mysqltablemodel.h
#ifndef MYSQLTABLEMODEL_H
#define MYSQLTABLEMODEL_H
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QSqlError>
#include <QSqlQuery>
#include <QDebug>
class MySqlTableModel : public QSqlTableModel
{
Q_OBJECT
public:
MySqlTableModel(QObject *parent = 0, QSqlDatabase db = QSqlDatabase());
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole ) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QHash<int, QByteArray> roles;
};
#endif // MYSQLTABLEMODEL_H
mysqltablemodel.cpp
#include "mysqltablemodel.h"
MySqlTableModel::MySqlTableModel(QObject *parent, QSqlDatabase db): QSqlTableModel(parent, db) {}
QVariant MySqlTableModel::data ( const QModelIndex & index, int role ) const
{
if(index.row() >= rowCount()) {
return QString("");
}
if(role < Qt::UserRole) {
return QSqlQueryModel::data(index, role);
}
else {
return QSqlQueryModel::data(this->index(index.row(), role - Qt::UserRole), Qt::DisplayRole);
}
}
QHash<int, QByteArray> MySqlTableModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Qt::UserRole + 1] = "name";
roles[Qt::UserRole + 2] = "salary";
return roles;
}

cannot resolve Qt's QMetaObject::invokeMethod: No such method error

I am trying to develop a generic function which determines whether two QObjects are equal. In order for this to be possible, the functions being compared must have an 'equals' method that compares various function values in each and returns true if they are all equal. Slso, this 'equal' method must be declared with Q_INVOKABLE.
However, when I attempt to call invokeMethod for the 'equals' method, it fails an an error "QMetaObject::invokeMethod: No such method F1::equals(QObject*)(QObject*)" is displayed.
Here is my test project and files:
Project file:
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
HEADERS += \
f1.h \
assert1.h
assert1.h
#ifndef ASSERT1_H
#define ASSERT1_H
#include <QObject>
#include <QDebug>
class Assert1 : public QObject
{
Q_OBJECT
public:
explicit Assert1(QObject *parent = nullptr) {}
static bool isEqual(QString msg, QObject* o1, QObject* o2)
{
if(o1 != nullptr && o2 != nullptr)
{
if(o1->metaObject()->className() != o2->metaObject()->className())
{
qDebug() << msg << " not same class type!";
return false;
}
const QMetaObject* metaObject =o1->metaObject();
int ix = metaObject->indexOfMethod(QMetaObject::normalizedSignature("equals(QObject *)"));
qDebug() << QMetaObject::normalizedSignature("equals(QObject *)");
if(ix == -1)
{
qDebug() << msg << tr("indexOfMethod(\"equals\") returns %1").arg(ix);
return false;
}
else
{
bool rslt = false;
if(!QMetaObject::invokeMethod(o1, QMetaObject::normalizedSignature("equals(QObject *)"),
Qt::DirectConnection,
Q_RETURN_ARG(bool, rslt),
Q_ARG(QObject*, o2)))
qDebug() << msg << tr("invoke method 'equals' failed for %1").arg(o1->metaObject()->className());
if(!rslt)
qDebug() << msg << tr(" objects not equal");
return false;
}
}
qDebug() << msg << "not equal";
}
signals:
public slots:
};
#endif // ASSERT1_H
f1.h
#ifndef F1_H
#define F1_H
#include <QObject>
#include <QDebug>
class F1 : public QObject
{
Q_OBJECT
public:
explicit F1(int p1, QString p2, QObject *parent = nullptr) : QObject(parent)
{
this->p1 = p1;
this->p2 = p2;
}
void setP1(int p) {this->p1 = p;}
void setP2(QString p) {this->p2 = p;}
Q_INVOKABLE bool equals(QObject* other)
{
if(qobject_cast<F1*>(other) != nullptr)
{
if(this->p1 != ((F1*)other)->p1)
return false;
if(this->p2 != ((F1*)other)->p2)
return false;
}
return true;
}
Q_INVOKABLE QString toString()
{
qDebug() << "p1 '" << p1 << " p2 = '" << p2 << "'";
}
signals:
public slots:
private:
int p1;
QString p2;
};
#endif // F1_H
main.cpp
#include <QCoreApplication>
#include "f1.h"
#include "assert1.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
F1* tf1 = new F1(1, "1");
F1* tf2 = new F1(1, "a");
F1* tf3 = new F1(1, "a");
F1* tf4 = new F1(4, "abc");
qDebug() << "tf1->equals(tf4) returns: " << (tf1->equals(tf4)?"true":"false");
qDebug() << "tf2->equals(tf3) returns: " << (tf2->equals(tf3)?"true":"false");
Assert1::isEqual("should be equal", (QObject*)tf2, (QObject*)tf3);
//return a.exec();
}
running the test produces this output:
Debugging starts
tf1->equals(tf4) returns: false
tf2->equals(tf3) returns: false
"equals(QObject*)"
QMetaObject::invokeMethod: No such method F1::equals(QObject*)(QObject*)
"should be equal" "invoke method 'equals' failed for F1"
How do I get invokeMethod to work?
The error in your case is that invokeMethod only waits for the name of the Q_SLOT or Q_INVOKABLE, does not need or want the signature, but you are passing it QMetaObject::normalizedSignature("equals(QObject*)") which returns "equals(QObject*)", so the solution is just to pass equals:
if(!QMetaObject::invokeMethod(o1, "equals",
Qt::DirectConnection,
Q_RETURN_ARG(bool, rslt),
Q_ARG(QObject*, o2)))

Equality operator for QFlags with scoped enum

I have some flags defined as follows, using a scoped enum:
enum class Capability : int
{
NoCapabilities = 0,
SomethingCool = 1,
UberCool = 1 << 1,
EvenCooler = 1 << 2,
};
Q_DECLARE_FLAGS( Capabilities, Capability )
Now, I am trying to use the equality operator:
Capabilities(DataCapability::NoCapabilities) == Capability::NoCapabilities
I cannot use testFlag in the current example, since NoCapabilities = 0. This works if the enum is not scoped (removing class keyword).
Apparently, casting to int (static_cast<int>(NoCapabilities)) works, but it's really ugly.
What is the approach to solve this?
Is it a bad practice to have a 0 zero value and test it?
You can overload equality operator for your combination of data types. However cast ist still necessary but hidden by operator.
#include <QCoreApplication>
#include <QFlags>
#include <iostream>
enum class Capability : int
{
NoCapabilities = 0,
SomethingCool = 1,
UberCool = (1 << 1),
EvenCooler = (1 << 2),
};
Q_DECLARE_FLAGS(Capabilities, Capability)
template <typename T>
bool operator==(const QFlags<T> lhs, const Capability rhs)
{
return (QFlags<T>::Int(lhs) == static_cast<int>(rhs));
}
int main(int argc, char *argv[])
{
Q_UNUSED(argc);
Q_UNUSED(argv);
if (Capabilities(Capability::NoCapabilities) == Capability::NoCapabilities)
{
std::cout << "true" << std::endl;
}
else
{
std::cout << "false" << std::endl;
}
if (Capabilities(Capability::EvenCooler) == Capability::NoCapabilities)
{
std::cout << "true" << std::endl;
}
else
{
std::cout << "false" << std::endl;
}
return 0;
}

Different color for different word in QML TextArea without RichText

I am trying to make a code editor and want to change color of keywords in TextArea after user types a keyword. I read that textFormat:Text.StyledText could change color without changing the whole text to Html but adding tags to the text is not changing the color. Here I used bold tag for code
Code -
TextArea{
Layout.alignment: Qt.AlignTop
id:ta
selectByMouse: true
selectByKeyboard: true
Layout.fillWidth:true
Layout.fillHeight: true
font.pointSize: 12
textMargin: 16
font.family:"courier new"
persistentSelection: true
textFormat: Text.StyledText
onActiveFocusChanged: {
menu_trig=0
}
onTextChanged: {
// check text
console.log(ta.text.slice(0,ta.text.length-3))
if(ta.text.slice(ta.text.length-3,ta.text.length)=="def")
{
ta_text.text=ta.text.substring(0,ta.text.length-3)+"<b>def</b>"}
}
Keys.onPressed: {
if(codeChange==0)
{codeChange=1
mainWindow.title=title.toString()+" *"}
}
Component.onCompleted: forceActiveFocus()
// color:"orange"}
You have to use a QSyntaxHighlighter and because it seems to me you are trying to make it an editor for python I have implemented based on this post.
syntaxhighlighter.h
#ifndef SYNTAXHIGHLIGHTER_H
#define SYNTAXHIGHLIGHTER_H
#include <QRegularExpression>
#include <QSyntaxHighlighter>
class QQuickTextDocument;
class HighlightingRule
{
public:
HighlightingRule(const QString &patternStr, int n, const QTextCharFormat &matchingFormat);
QString originalRuleStr;
QRegularExpression pattern;
int nth;
QTextCharFormat format;
};
class PythonSyntaxHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
PythonSyntaxHighlighter(QTextDocument *parent);
const QTextCharFormat getTextCharFormat(const QString &colorName, const QString &style = QString());
void initializeRules();
bool matchMultiline(const QString &text, const QRegularExpression &delimiter, const int inState, const QTextCharFormat &style);
protected:
void highlightBlock(const QString &text);
private:
QStringList keywords;
QStringList operators;
QStringList braces;
QHash<QString, QTextCharFormat> basicStyles;
QList<HighlightingRule> rules;
QRegularExpression triSingleQuote;
QRegularExpression triDoubleQuote;
};
class SyntaxHighlighterHelper: public QObject
{
Q_OBJECT
Q_PROPERTY(QQuickTextDocument *quickdocument READ quickdocument WRITE setQuickdocument NOTIFY quickdocumentChanged)
public:
SyntaxHighlighterHelper(QObject *parent=nullptr):
QObject(parent),
m_quickdocument(nullptr)
{}
QQuickTextDocument *quickdocument() const;
void setQuickdocument(QQuickTextDocument *quickdocument);
signals:
void quickdocumentChanged();
private:
QQuickTextDocument *m_quickdocument;
};
#endif // SYNTAXHIGHLIGHTER_H
syntaxhighlighter.cpp
#include "syntaxhighlighter.h"
#include <QQuickTextDocument>
HighlightingRule::HighlightingRule(const QString &patternStr, int n, const QTextCharFormat &matchingFormat)
{
originalRuleStr = patternStr;
pattern = QRegularExpression(patternStr);
nth = n;
format = matchingFormat;
}
PythonSyntaxHighlighter::PythonSyntaxHighlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
keywords = QStringList() << "and" << "assert" << "break" << "class" << "continue" << "def" <<
"del" << "elif" << "else" << "except" << "exec" << "finally" <<
"for" << "from" << "global" << "if" << "import" << "in" <<
"is" << "lambda" << "not" << "or" << "pass" << "print" <<
"raise" << "return" << "try" << "while" << "yield" <<
"None" << "True" << "False";
operators = QStringList() << "=" <<
// Comparison
"==" << "!=" << "<" << "<=" << ">" << ">=" <<
// Arithmetic
"\\+" << "-" << "\\*" << "/" << "//" << "%" << "\\*\\*" <<
// In-place
"\\+=" << "-=" << "\\*=" << "/=" << "%=" <<
// Bitwise
"\\^" << "\\|" << "&" << "~" << ">>" << "<<";
braces = QStringList() << "{" << "}" << "\\(" << "\\)" << "\\[" << "]";
basicStyles.insert("keyword", getTextCharFormat("blue"));
basicStyles.insert("operator", getTextCharFormat("red"));
basicStyles.insert("brace", getTextCharFormat("darkGray"));
basicStyles.insert("defclass", getTextCharFormat("black", "bold"));
basicStyles.insert("brace", getTextCharFormat("darkGray"));
basicStyles.insert("string", getTextCharFormat("magenta"));
basicStyles.insert("string2", getTextCharFormat("darkMagenta"));
basicStyles.insert("comment", getTextCharFormat("darkGreen", "italic"));
basicStyles.insert("self", getTextCharFormat("black", "italic"));
basicStyles.insert("numbers", getTextCharFormat("brown"));
triSingleQuote.setPattern("'''");
triDoubleQuote.setPattern("\"\"\"");
initializeRules();
}
void PythonSyntaxHighlighter::initializeRules()
{
for(const QString & currKeyword: keywords)
{
rules.append(HighlightingRule(QString("\\b%1\\b").arg(currKeyword), 0, basicStyles.value("keyword")));
}
for(const QString & currOperator: operators)
{
rules.append(HighlightingRule(QString("%1").arg(currOperator), 0, basicStyles.value("operator")));
}
for(const QString &currBrace: braces)
{
rules.append(HighlightingRule(QString("%1").arg(currBrace), 0, basicStyles.value("brace")));
}
// 'self'
rules.append(HighlightingRule("\\bself\\b", 0, basicStyles.value("self")));
// Double-quoted string, possibly containing escape sequences
// FF: originally in python : r'"[^"\\]*(\\.[^"\\]*)*"'
rules.append(HighlightingRule("\"[^\"\\\\]*(\\\\.[^\"\\\\]*)*\"", 0, basicStyles.value("string")));
// Single-quoted string, possibly containing escape sequences
// FF: originally in python : r"'[^'\\]*(\\.[^'\\]*)*'"
rules.append(HighlightingRule("'[^'\\\\]*(\\\\.[^'\\\\]*)*'", 0, basicStyles.value("string")));
// 'def' followed by an identifier
// FF: originally: r'\bdef\b\s*(\w+)'
rules.append(HighlightingRule("\\bdef\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
// 'class' followed by an identifier
// FF: originally: r'\bclass\b\s*(\w+)'
rules.append(HighlightingRule("\\bclass\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
// From '#' until a newline
// FF: originally: r'#[^\\n]*'
rules.append(HighlightingRule("#[^\\n]*", 0, basicStyles.value("comment")));
// Numeric literals
rules.append(HighlightingRule("\\b[+-]?[0-9]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+[lL]?\b'
rules.append(HighlightingRule("\\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b'
rules.append(HighlightingRule("\\b[+-]?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b'
}
void PythonSyntaxHighlighter::highlightBlock(const QString &text)
{
for(const HighlightingRule &rule: rules) {
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
bool isInMultilne = matchMultiline(text, triSingleQuote, 1, basicStyles.value("string2"));
if (!isInMultilne)
isInMultilne = matchMultiline(text, triDoubleQuote, 2, basicStyles.value("string2"));
}
bool PythonSyntaxHighlighter::matchMultiline(const QString &text, const QRegularExpression &delimiter, const int inState, const QTextCharFormat &style)
{
QRegularExpressionMatch match;
int startIndex = 0;
if (previousBlockState() != 1)
startIndex = text.indexOf(delimiter);
while (startIndex >= 0) {
QRegularExpressionMatch match = delimiter.match(text, startIndex);
int endIndex = match.capturedStart();
int commentLength = 0;
if (endIndex == -1) {
setCurrentBlockState(1);
commentLength = text.length() - startIndex;
} else {
commentLength = endIndex - startIndex
+ match.capturedLength();
}
setFormat(startIndex, commentLength, style);
startIndex = text.indexOf(delimiter, startIndex + commentLength);
}
return currentBlockState() == inState;
}
const QTextCharFormat PythonSyntaxHighlighter::getTextCharFormat(const QString &colorName, const QString &style)
{
QTextCharFormat charFormat;
QColor color(colorName);
charFormat.setForeground(color);
if (style.contains("bold", Qt::CaseInsensitive))
charFormat.setFontWeight(QFont::Bold);
if (style.contains("italic", Qt::CaseInsensitive))
charFormat.setFontItalic(true);
return charFormat;
}
QQuickTextDocument *SyntaxHighlighterHelper::quickdocument() const
{
return m_quickdocument;
}
void SyntaxHighlighterHelper::setQuickdocument(QQuickTextDocument *quickdocument)
{
m_quickdocument = quickdocument;
if(m_quickdocument){
new PythonSyntaxHighlighter(m_quickdocument->textDocument());
}
}
main.cpp
// ...
qmlRegisterType<SyntaxHighlighterHelper>("Foo", 1, 0, "SyntaxHighlighterHelper");
// ...
main.qml
// ...
import Foo 1.0
// ...
SyntaxHighlighterHelper{
quickdocument: ta.textDocument
}
TextArea{
id:ta
anchors.fill: parent
selectByMouse: true
selectByKeyboard: true
font.pointSize: 12
textMargin: 16
font.family:"courier new"
persistentSelection: true
textFormat: Text.StyledText
tabStopDistance: 4*fontMetrics.advanceWidth(" ")
FontMetrics {
id: fontMetrics
font.family: ta.font
}
}
// ...
The example can be found here.

"usage:\n\tll '(a+a)'" meaning in ll1 parser program

I am unable to understand what is the role of "usage:\n\tll '(a+a)'" in the code. What is its function?? I am using g++ compiler to compile the code. If more than 2 arguments are passed in command prompt then problem occurs.
#include <iostream>
#include <map>
#include <stack>
enum Symbols {
TS_L_PARENS,
TS_R_PARENS,
TS_A,
TS_PLUS,
TS_EOS,
TS_INVALID,
NTS_S,
NTS_F
};
enum Symbols lexer(char c)
{
switch(c)
{
case '(': return TS_L_PARENS;
case ')': return TS_R_PARENS;
case 'a': return TS_A;
case '+': return TS_PLUS;
case '\0': return TS_EOS;
default: return TS_INVALID;
}
}
int main(int argc, char **argv)
{
using namespace std;
if (argc < 2)
{
cout << **"usage:\n\tll '(a+a)'"** << endl;
return 0;
}
map< enum Symbols, map<enum Symbols, int> > table;
stack<enum Symbols> ss; // symbol stack
char *p; // input buffer
ss.push(TS_EOS); // terminal, $
ss.push(NTS_S); // non-terminal, S
p = &argv[1][0];
table[NTS_S][TS_L_PARENS] = 2;
table[NTS_S][TS_A] = 1;
table[NTS_F][TS_A] = 3;
while(ss.size() > 0)
{
if(lexer(*p) == ss.top())
{
cout << "Matched symbols: " << lexer(*p) << endl;
p++;
ss.pop();
}
else
{
cout << "Rule " << table[ss.top()][lexer(*p)] << endl;
switch(table[ss.top()][lexer(*p)])
{
case 1: // 1. S → F
ss.pop();
ss.push(NTS_F); // F
break;
case 2: // 2. S → ( S + F )
ss.pop();
ss.push(TS_R_PARENS); // )
ss.push(NTS_F); // F
ss.push(TS_PLUS); // +
ss.push(NTS_S); // S
ss.push(TS_L_PARENS); // (
break;
case 3: // 3. F → a
ss.pop();
ss.push(TS_A); // a
break;
default:
cout << "parsing table defaulted" << endl;
return 0;
break;
}
}
}
cout << "finished parsing" << endl;
return 0;
}
cout is the function, "usage:\n\tll '(a+a)'" is a string literal passed to the function. This bit in your question prints:
usage:
ll '(a+a)'

Resources