You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/microbe/parser.h

294 lines
9.0 KiB

/***************************************************************************
* Copyright (C) 2004-2005 by Daniel Clarke *
* daniel.jc@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef PARSER_H
#define PARSER_H
#include "expression.h"
#include "instruction.h"
#include "microbe.h"
#include "tqmap.h"
#include "tqvaluelist.h"
class PIC14;
/**
@author Daniel Clarke
@author David Saxton
*/
class Statement
{
public:
/**
* Is the assembly output generated for this statement.
*/
InstructionList * code;
/**
* The original microbe source line.
*/
SourceLine content;
/**
* Returns the microbe code from content.
*/
TQString text() const { return content.text(); }
/**
* If this Statement is for a for loop, then content will contain
* something like "for x = 1 to 10", and bracedCode will contain the
* source code within (but not including) the braces.
*/
SourceLineList bracedCode;
/**
* Just returns whether or not the braced code is empty.
*/
bool hasBracedCode() const { return !bracedCode.isEmpty(); }
/**
* This breaks up the line seperated by spaces,{,and =/
*/
static TQStringList tokenise(const TQString &line);
/**
* @see tokenise(const TQString &line)
*/
TQStringList tokenise() const { return tokenise( content.text() ); }
/**
* @returns whether or not the content looks like a label (ends with a
* colon).
*/
bool isLabel() const { return content.text().right(1) == ":"; }
};
typedef TQValueList<Statement> StatementList;
/**
@author Daniel Clarke
@author David Saxton
*/
class Field
{
public:
enum Type
{
// String that doesn't change the program logic, but might or might
// not need to be there depending on the statement (e.g. "then" in
// the if-statement).
FixedString,
// Label, Variable, Name are all treated similarly (only different
// error messages are given).
Label, // e.g. in "goto [Label]"
Variable, // e.g. in "increment [Variable]"
Name, // e.g. in "sevenseg [Name]"
// List of strings which should be pin names.
PinList,
// Braced code.
Code,
Expression,
Newline,
None
};
/**
* Create a Field of type None.
*/
Field();
/**
* Create a Field.
*/
Field( Type type, const TQString & key = 0 );
/**
* Create a Field (this constructor should only be used with
* FixedStrings.
*/
Field( Type type, const TQString & key, const TQString & string, bool compulsory = true);
/**
* The type of field expected.
*/
Type type() const { return m_type; }
/**
* String data relevant to the field dependent on m_type.
*/
TQString string() const { return m_string; }
/**
* The key in which the found token will be attached to
* in the output map. If it is an empty string, then the field will be
* processed but not put in the output, effectively ignoring it.
*/
TQString key() const { return m_key; }
/**
* Only FixedStrings may be compulsory, that is the only type that can
* actually have its presence checked.
* This flag is set to indicate that no error should be rasied if the
* field is not present. Note that if a field is found missing, then
* the rest of the statement is ignored (regardless of whether the rest
* is marked compulsory or not.)
*/
bool compulsory() const { return m_compulsory; }
private:
Type m_type;
TQString m_string;
TQString m_key;
bool m_compulsory;
};
class OutputField
{
public:
/**
* Constructs an empty output field.
*/
OutputField();
/**
* Constructs an output field consisting of braced code.
*/
OutputField( const SourceLineList & bracedCode );
/**
* Constructs an output field consisting of a single string.
*/
OutputField( const TQString &string );
TQString string() const { return m_string; }
SourceLineList bracedCode() const { return m_bracedCode; }
bool found() const { return m_found; }
private:
TQString m_string;
SourceLineList m_bracedCode;
/**
* This specifies if a non compulsory field was found or not.
*/
bool m_found;
};
typedef TQValueList<Field> StatementDefinition;
typedef TQMap<TQString,StatementDefinition> DefinitionMap;
typedef TQMap<TQString,OutputField> OutputFieldMap;
/**
@author Daniel Clarke
@author David Saxton
*/
class Parser
{
public:
Parser( Microbe * mb );
~Parser();
/**
* Report a compile error to Microbe; the current source line will be
* sent. Context is extra information to be inserted into the error
* message, only applicable to some errors (such as a use of a reserved
* keyword).
*/
void mistake( Microbe::MistakeType type, const TQString & context = 0 );
/**
* Creates a new instance of the parser class with all state information
* (class members) copied from this instance of the class. Don't forget to
* delete it when you are done!
*/
Parser * createChildParser();
/**
* Creates a child class and uses it to parse recursively.
*/
Code * parseWithChild( const SourceLineList & lines );
/**
* This is the actual parsing function, make sure to use parseUsingChild
* instead (???)
*/
Code * parse( const SourceLineList & lines );
/**
* Returns the lines between the braces, excluding the braces, e.g.
* defproc name
* {
* more code
* some more code
* }
* returns ("more code","some more code").
* Note that Microbe has already put the braces on separate lines for us.
* @param it is the iterator at the position of the first brace, this
* function will return with it pointing at the matching closing brace.
* @param end is the iterator pointing to the end of the source line
* list, so that we don't search past it.
* @returns The braced code (excluding the braces).
*/
SourceLineList getBracedCode( SourceLineList::const_iterator * it, SourceLineList::const_iterator end );
/**
* Returns expression type.
* 0 = directly usable number (literal).
* 1 = variable.
* 2 = expression that needs evaluating.
*/
ExprType getExpressionType( const TQString & expression );
/**
* Examines the text to see if it looks like a literal, i.e. of the form
* "321890","021348","0x3C","b'0100110'","0101001b","h'43A'", or "2Ah".
* Everything else is considered non-literal.
* @see literalToInt.
*/
static bool isLiteral( const TQString &text );
/**
* Tries to convert the given literal string into a integer. If it fails,
* i.e. it is not any recognised literal, then it returns -1 and sets *ok to
* false. Else, *ok is set to true and the literal value is returned.
* @see isLiteral
*/
static int literalToInt( const TQString & literal, bool * ok = 0l );
/**
* Does the specified operation on the given numbers and returns the result.
*/
static int doArithmetic( int lvalue, int rvalue, Expression::Operation op );
/**
* @return whether it was an assignment (which might not have been in
* the proper form).
*/
bool processAssignment(const TQString &line);
void compileConditionalExpression( const TQString & expression, Code * ifCode, Code * elseCode ) const;
TQString processConstant(const TQString &expression, bool * isConstant, bool suppressNumberTooBig = false) const;
private:
/**
* This is called when the bulk of the actual parsing has been carried
* out and is ready to be turned into assembly code.
* @param name Name of the statement to be processed
* @param fieldMap A map of named fields as appropriate to the statement
*/
void processStatement( const TQString & name, const OutputFieldMap & fieldMap );
DefinitionMap m_definitionMap;
PIC14 * m_pPic;
bool m_bPassedEnd;
Microbe * mb;
Code * m_code;
SourceLine m_currentSourceLine;
private: // Disable copy constructor and operator=
Parser( const Parser & );
Parser &operator=( const Parser & );
};
#endif