File indexing completed on 2024-07-21 08:05:27

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2005 by Daniel Clarke                              *
0003  *   daniel.jc@gmail.com                                                   *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 
0021 #ifndef PARSER_H
0022 #define PARSER_H
0023 
0024 #include "expression.h"
0025 #include "instruction.h"
0026 #include "microbe.h"
0027 
0028 #include <QMap>
0029 #include <QList>
0030 
0031 class PIC14;
0032 
0033 /**
0034 @author Daniel Clarke
0035 @author David Saxton
0036 */
0037 class Statement
0038 {
0039     public:
0040         Statement();
0041 
0042         /**
0043          * Is the assembly output generated for this statement.
0044          */
0045         InstructionList * code;
0046         /**
0047          * The original microbe source line.
0048          */
0049         SourceLineMicrobe content;
0050         /**
0051          * Returns the microbe code from content.
0052          */
0053         QString text() const { return content.text(); }
0054         /**
0055          * If this Statement is for a for loop, then content will contain
0056          * something like "for x = 1 to 10", and bracedCode will contain the
0057          * source code within (but not including) the braces.
0058          */
0059         SourceLineList bracedCode;
0060         /**
0061          * Just returns whether or not the braced code is empty.
0062          */
0063         bool hasBracedCode() const { return !bracedCode.isEmpty(); }
0064         /**
0065          * This breaks up the line separated by spaces,{,and =/
0066          */
0067         static QStringList tokenise(const QString &line);
0068         /**
0069          * @see tokenise(const QString &line)
0070          */
0071         QStringList tokenise() const { return tokenise( content.text() ); }
0072         /**
0073          * @returns whether or not the content looks like a label (ends with a
0074          * colon).
0075          */
0076         bool isLabel() const { return content.text().right(1) == ":"; }
0077 };
0078 
0079 typedef QList<Statement> StatementList;
0080 
0081 /**
0082 @author Daniel Clarke
0083 @author David Saxton
0084 */
0085 class Field
0086 {
0087     public:
0088         enum Type
0089         {
0090             // String that doesn't change the program logic, but might or might
0091             // not need to be there depending on the statement (e.g. "then" in
0092             // the if-statement).
0093             FixedString,
0094             
0095             // Label, Variable, Name are all treated similarly (only different
0096             // error messages are given).
0097             Label, // e.g. in "goto [Label]"
0098             Variable, // e.g. in "increment [Variable]"
0099             Name, // e.g. in "sevenseg [Name]"
0100             
0101             // List of strings which should be pin names.
0102             PinList,
0103             
0104             // Braced code.
0105             Code,
0106             
0107             Expression,
0108             Newline,
0109             None
0110         };
0111     
0112         /**
0113          * Create a Field of type None.
0114          */
0115         Field();
0116         /**
0117          * Create a Field.
0118          */
0119         Field( Type type, const QString & key = nullptr );
0120         /**
0121          * Create a Field (this constructor should only be used with
0122          * FixedStrings.
0123          */
0124         Field( Type type, const QString & key, const QString & string, bool compulsory = true);
0125         
0126         /**
0127          * The type of field expected.
0128          */
0129         Type type() const { return m_type; }
0130         /**
0131          * String data relevant to the field dependent on m_type.
0132          */
0133         QString string() const { return m_string; }
0134         /**
0135          * The key in which the found token will be attached to 
0136          * in the output map. If it is an empty string, then the field will be 
0137          * processed but not put in the output, effectively ignoring it.
0138          */
0139         QString key() const { return m_key; }
0140         /**
0141          * Only FixedStrings may be compulsory, that is the only type that can
0142          * actually have its presence checked.
0143          * This flag is set to indicate that no error should be rasied if the 
0144          * field is not present. Note that if a field is found missing, then
0145          * the rest of the statement is ignored (regardless of whether the rest
0146          * is marked compulsory or not.)
0147          */
0148         bool compulsory() const { return m_compulsory; }
0149     
0150     private:
0151         Type m_type;
0152         QString m_string;
0153         QString m_key;
0154         bool m_compulsory;
0155 };
0156 
0157 
0158 class OutputField
0159 {
0160     public:
0161         /**
0162          * Constructs an empty output field.
0163          */
0164         OutputField();
0165         /**
0166          * Constructs an output field consisting of braced code.
0167          */
0168         OutputField( const SourceLineList & bracedCode );
0169         /**
0170          * Constructs an output field consisting of a single string.
0171          */
0172         OutputField( const QString &string );
0173     
0174         QString string() const { return m_string; }
0175         SourceLineList bracedCode() const { return m_bracedCode; }
0176         bool found() const { return m_found; }
0177     
0178     private:
0179         QString m_string;
0180         SourceLineList m_bracedCode;
0181         /**
0182          * This specifies if a non compulsory field was found or not.
0183          */
0184         bool m_found;
0185 };
0186 
0187 typedef QList<Field> StatementDefinition;
0188 typedef QMap<QString,StatementDefinition> DefinitionMap;
0189 typedef QMap<QString,OutputField> OutputFieldMap;
0190 
0191 
0192 /**
0193 @author Daniel Clarke
0194 @author David Saxton
0195 */
0196 class Parser
0197 {
0198     public:
0199         Parser( MicrobeApp * mb );
0200         ~Parser();
0201     
0202         /**
0203          * Report a compile error to MicrobeApp; the current source line will be
0204          * sent. Context is extra information to be inserted into the error
0205          * message, only applicable to some errors (such as a use of a reserved
0206          * keyword).
0207          */
0208         void mistake( MicrobeApp::MistakeType type, const QString & context = nullptr );
0209         /**
0210          * Creates a new instance of the parser class with all state information
0211          * (class members) copied from this instance of the class. Don't forget to
0212          * delete it when you are done!
0213          */
0214         Parser * createChildParser();
0215         /**
0216          * Creates a child class and uses it to parse recursively.
0217          */
0218         Code * parseWithChild( const SourceLineList & lines );
0219         /**
0220          * This is the actual parsing function, make sure to use parseUsingChild
0221          * instead (???)
0222          */
0223         Code * parse( const SourceLineList & lines );
0224         /**
0225          * Returns the lines between the braces, excluding the braces, e.g.
0226          * defproc name
0227          * {
0228          * more code 
0229          * some more code
0230          * }
0231          * returns ("more code","some more code").
0232          * Note that MicrobeApp has already put the braces on separate lines for us.
0233          * @param it is the iterator at the position of the first brace, this
0234          * function will return with it pointing at the matching closing brace.
0235          * @param end is the iterator pointing to the end of the source line
0236          * list, so that we don't search past it.
0237          * @returns The braced code (excluding the braces).
0238          */
0239         SourceLineList getBracedCode( SourceLineList::const_iterator * it, SourceLineList::const_iterator end );
0240         /**
0241          * Returns expression type.
0242          * 0 = directly usable number (literal).
0243          * 1 = variable.
0244          * 2 = expression that needs evaluating.
0245          */
0246         ExprType getExpressionType( const QString & expression );
0247         /**
0248          * Examines the text to see if it looks like a literal, i.e. of the form
0249          * "321890","021348","0x3C","b'0100110'","0101001b","h'43A'", or "2Ah".
0250          * Everything else is considered non-literal.
0251          * @see literalToInt.
0252          */
0253         static bool isLiteral( const QString &text );
0254         /**
0255          * Tries to convert the given literal string into a integer. If it fails,
0256          * i.e. it is not any recognised literal, then it returns -1 and sets *ok to
0257          * false. Else, *ok is set to true and the literal value is returned.
0258          * @see isLiteral
0259          */
0260         static int literalToInt( const QString & literal, bool * ok = nullptr );
0261         /**
0262          * Does the specified operation on the given numbers and returns the result.
0263          */
0264         static int doArithmetic( int lvalue, int rvalue, Expression::Operation op );
0265         /**
0266          * @return whether it was an assignment (which might not have been in
0267          * the proper form).
0268          */
0269         bool processAssignment(const QString &line);
0270     
0271         void compileConditionalExpression( const QString & expression, Code * ifCode, Code * elseCode ) const;
0272         QString processConstant(const QString &expression, bool * isConstant, bool suppressNumberTooBig = false) const;
0273     
0274     private:
0275         /**
0276          * This is called when the bulk of the actual parsing has been carried
0277          * out and is ready to be turned into assembly code.
0278          * @param name Name of the statement to be processed
0279          * @param fieldMap A map of named fields as appropriate to the statement
0280          */
0281         void processStatement( const QString & name, const OutputFieldMap & fieldMap );
0282 
0283         DefinitionMap m_definitionMap;
0284         PIC14 * m_pPic;
0285         bool m_bPassedEnd;
0286         MicrobeApp * mb;
0287         Code * m_code;
0288         SourceLineMicrobe m_currentSourceLine;
0289         
0290     private: // Disable copy constructor and operator=
0291         Parser( const Parser & );
0292         Parser &operator=( const Parser & );
0293 };
0294 
0295 #endif