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 #include "btreebase.h"
0022 #include "expression.h"
0023 #include "instruction.h"
0024 #include "parser.h"
0025 #include "pic14.h"
0026 #include "traverser.h"
0027 
0028 #include <cassert>
0029 #include <QDebug>
0030 #include <QFile>
0031 #include <QRegExp>
0032 #include <QString>
0033 
0034 #include <iostream>
0035 using namespace std;
0036 
0037 
0038 //BEGIN class Parser
0039 Parser::Parser( MicrobeApp * _mb )
0040 {
0041     m_code = nullptr;
0042     m_pPic = nullptr;
0043     mb = _mb;
0044     // Set up statement definitions.
0045     StatementDefinition definition;
0046 
0047     definition.append( Field(Field::Label, "label") );
0048     m_definitionMap["goto"] = definition;
0049     definition.clear();
0050 
0051     definition.append( Field(Field::Label, "label") );
0052     m_definitionMap["call"] = definition;
0053     definition.clear();
0054 
0055     definition.append( Field(Field::Expression, "expression") );
0056     definition.append( Field(Field::Code, "code") );
0057     m_definitionMap["while"] = definition;
0058     definition.clear();
0059 
0060     m_definitionMap["end"] = definition;
0061     definition.clear();
0062 
0063     definition.append( Field(Field::Label, "label") );
0064     definition.append( Field(Field::Code, "code") );
0065     // For backwards compataibility
0066     m_definitionMap["sub"] = definition;
0067     m_definitionMap["subroutine"] = definition;
0068     definition.clear();
0069 
0070     definition.append( Field(Field::Label, "label") );
0071     definition.append( Field(Field::Code, "code") );
0072     m_definitionMap["interrupt"] = definition;
0073     definition.clear();
0074 
0075     definition.append( Field(Field::Label, "alias") );
0076     definition.append( Field(Field::Label, "dest") );
0077     m_definitionMap["alias"] = definition;
0078     definition.clear();
0079 
0080     definition.append( Field(Field::Expression, "expression") );
0081     definition.append( Field(Field::FixedString, nullptr, "then", true) );
0082     definition.append( Field(Field::Code, "ifCode") );
0083     definition.append( Field(Field::Newline) );
0084     definition.append( Field(Field::FixedString, nullptr, "else", false) );
0085     definition.append( Field(Field::Code, "elseCode") );
0086     m_definitionMap["if"] = definition;
0087     definition.clear();
0088 
0089     definition.append( Field(Field::Expression, "initExpression") );
0090     definition.append( Field(Field::FixedString, nullptr, "to", true) );
0091     definition.append( Field(Field::Expression, "toExpression") );
0092     definition.append( Field(Field::FixedString, nullptr, "step", false) );
0093     definition.append( Field(Field::Expression, "stepExpression") );
0094     definition.append( Field(Field::Code, "code") );
0095     m_definitionMap["for"] = definition;
0096     definition.clear();
0097 
0098     definition.append( Field(Field::Variable, "variable") );
0099     m_definitionMap["decrement"] = definition;
0100     definition.clear();
0101 
0102     definition.append( Field(Field::Variable, "variable") );
0103     m_definitionMap["increment"] = definition;
0104     definition.clear();
0105 
0106     definition.append( Field(Field::Variable, "variable") );
0107     m_definitionMap["rotateleft"] = definition;
0108     definition.clear();
0109 
0110     definition.append( Field(Field::Variable, "variable") );
0111     m_definitionMap["rotateright"] = definition;
0112     definition.clear();
0113 
0114     definition.append( Field(Field::Code, "code") );
0115     m_definitionMap["asm"] = definition;
0116     definition.clear();
0117 
0118     definition.append( Field(Field::Expression, "expression") );
0119     m_definitionMap["delay"] = definition;
0120     definition.clear();
0121 
0122     definition.append( Field(Field::Code, "code") );
0123     definition.append( Field(Field::Newline) );
0124     definition.append( Field(Field::FixedString, nullptr, "until", true) );
0125     definition.append( Field(Field::Expression, "expression") );
0126     m_definitionMap["repeat"] = definition;
0127     definition.clear();
0128 
0129     definition.append( Field(Field::Name, "name") );
0130     definition.append( Field(Field::PinList, "pinlist") );
0131     m_definitionMap["sevenseg"] = definition;
0132     definition.clear();
0133 
0134     definition.append( Field(Field::Name, "name") );
0135     definition.append( Field(Field::PinList, "pinlist") );
0136     m_definitionMap["keypad"] = definition;
0137     definition.clear();
0138 }
0139 
0140 Parser::~Parser()
0141 {
0142 }
0143 
0144 Parser* Parser::createChildParser()
0145 {
0146     Parser * parser = new Parser( mb );
0147 
0148     return parser;
0149 }
0150 
0151 
0152 Code * Parser::parseWithChild( const SourceLineList & lines )
0153 {
0154     Parser * p = createChildParser();
0155     Code * code = p->parse(lines);
0156     delete p;
0157     return code;
0158 }
0159 
0160 
0161 Code * Parser::parse( const SourceLineList & lines )
0162 {
0163     StatementList sList;
0164     m_pPic = mb->makePic();
0165     m_code = new Code();
0166     m_pPic->setCode( m_code );
0167     m_pPic->setParser(this);
0168     m_bPassedEnd = false;
0169 
0170     /* First pass
0171        ==========
0172 
0173        Here we go through the code making each line into a statement object,
0174        looking out for braced code as we go, if we find it then we put then
0175        we make attach the braced code to the statment.
0176     */
0177 
0178     SourceLineList::const_iterator end = lines.end();
0179     for ( SourceLineList::const_iterator slit = lines.begin(); slit != end; ++slit )
0180     {
0181         Statement s;
0182         s.content = *slit;
0183 
0184         // Check to see if the line after next is a brace
0185         SourceLineList::const_iterator previous = slit;
0186         if ( (++slit != end) && (*slit).text() == "{" )
0187             s.bracedCode = getBracedCode( & slit, end );
0188         else
0189             slit = previous;
0190 
0191         if ( !s.text().isEmpty() )
0192             sList.append(s);
0193     }
0194 
0195     mb->resetDest();
0196 
0197     for( StatementList::Iterator sit = sList.begin(); sit != sList.end(); ++sit )
0198     {
0199         m_currentSourceLine = (*sit).content;
0200 
0201         QString line = (*sit).text();
0202 
0203         QString command; // e.g. "delay", "for", "subroutine", "increment", etc
0204         {
0205             int spacepos = line.indexOf(' ');
0206             if ( spacepos >= 0 )
0207                 command = line.left( spacepos );
0208             else
0209                 command = line;
0210         }
0211         OutputFieldMap fieldMap;
0212 
0213         if ( (*sit).content.line() >= 0 )
0214             m_code->append( new Instr_sourceCode( QString("#MSRC\t%1; %2\t%3").arg( (*sit).content.line() + 1 ).arg( (*sit).content.url() ).arg( (*sit).content.text() ) ));
0215         bool showBracesInSource = (*sit).hasBracedCode();
0216         if ( showBracesInSource )
0217             m_code->append(new Instr_sourceCode("{"));
0218 
0219         // Use the first token in the line to look up the statement type
0220         DefinitionMap::Iterator dmit = m_definitionMap.find(command);
0221         if(dmit == m_definitionMap.end())
0222         {
0223             if( !processAssignment( (*sit).text() ) )
0224             {
0225                 // Not an assignement, maybe a label
0226                 if( (*sit).isLabel() )
0227                 {
0228                     QString label = (*sit).text().left( (*sit).text().length() - 1 );
0229                     ///TODO sanity check label name and then do error like "Bad label"
0230                     m_pPic->Slabel( label );
0231                 }
0232                 else
0233                     mistake( MicrobeApp::MicrobeApp::UnknownStatement );
0234             }
0235 
0236             continue; // Give up on the current statement
0237         }
0238         StatementDefinition definition = dmit.value();
0239 
0240         // Start at the first white space character following the statement name
0241         int newPosition = 0;
0242         int position = command.length() + 1;
0243 
0244         // Temporaries for use inside the switch
0245         Field nextField;
0246         Statement nextStatement;
0247 
0248         bool errorInLine = false;
0249         bool finishLine = false;
0250 
0251         for( StatementDefinition::Iterator sdit = definition.begin(); sdit != definition.end(); ++sdit )
0252         {
0253             // If there is an error, or we have finished the statement,
0254             // the stop. If we are at the end of a line in a multiline, then
0255             // break to fall through to the next line
0256             if( errorInLine || finishLine) break;
0257 
0258             Field field = (*sdit);
0259             QString token;
0260 
0261             bool saveToken = false;
0262             bool saveBraced = false;
0263             bool saveSingleLine = false;
0264 
0265             switch(field.type())
0266             {
0267                 case (Field::Label):
0268                 case (Field::Variable):
0269                 case (Field::Name):
0270                 {
0271                     newPosition = line.indexOf( ' ', position );
0272                     if(position == newPosition)
0273                     {
0274                         newPosition = -1;
0275                         token = line.mid(position);
0276                     }
0277                     else token = line.mid(position, newPosition - position);
0278                     if( token.isEmpty() )
0279                     {
0280                         if(field.type() == Field::Label)
0281                             mistake( MicrobeApp::MicrobeApp::LabelExpected );
0282                         else if (field.type() == Field::Variable)
0283                             mistake( MicrobeApp::VariableExpected );
0284                         else // field.type() == Field::Name
0285                             mistake( MicrobeApp::NameExpected );
0286                         errorInLine = true;
0287                         continue;
0288                     }
0289                     position = newPosition;
0290                     saveToken = true;
0291                     break;
0292                 }
0293 
0294                 case (Field::Expression):
0295                 {
0296                     // This is slightly different, as there is nothing
0297                     // in particular that delimits an expression, we just have to
0298                     // look at what comes next and hope we can use that.
0299                     StatementDefinition::Iterator it(sdit);
0300                     ++it;
0301                     if( it != definition.end() )
0302                     {
0303                         nextField = (*it);
0304                         if(nextField.type() == Field::FixedString)
0305                             newPosition = line.indexOf(QRegExp("\\b" + nextField.string() + "\\b"));
0306                         // Although code is not neccessarily braced, after an expression it is the only
0307                         // sensilbe way to have it.
0308                         else if(nextField.type() == Field::Code)
0309                         {
0310                             newPosition = line.indexOf("{");
0311                             if(newPosition == -1) newPosition = line.length() + 1;
0312                         }
0313                         else if(nextField.type() == Field::Newline)
0314                             newPosition = line.length()+1;
0315                         else qDebug() << "Bad statement definition - awkward field type after expression";
0316                     }
0317                     else newPosition = line.length() + 1;
0318                     if(newPosition == -1)
0319                     {
0320                         // Something was missing, we'll just play along for now,
0321                         // the next iteration will catch whatever was supposed to be there
0322                     }
0323                     token = line.mid(position, newPosition - position);
0324                     position = newPosition;
0325                     saveToken = true;
0326                 }
0327                 break;
0328 
0329                 case (Field::PinList):
0330                 {
0331                     // For now, just assume that the list of pins will continue to the end of the tokens.
0332                     // (we could check until we come across a non-pin, but no command has that format at
0333                     // the moment).
0334 
0335                     token = line.mid( position + 1 );
0336                     position = line.length() + 1;
0337                     if ( token.isEmpty() )
0338                         mistake( MicrobeApp::PinListExpected );
0339                     else
0340                         saveToken = true;
0341 
0342                     break;
0343                 }
0344 
0345                 case (Field::Code):
0346                     if ( !(*sit).hasBracedCode() )
0347                     {
0348                         saveSingleLine = true;
0349                         token = line.mid(position);
0350                         position = line.length() + 1;
0351                     }
0352                     else if( position != -1  && position <= int(line.length()) )
0353                     {
0354                         mistake( MicrobeApp::UnexpectedStatementBeforeBracket );
0355                         errorInLine = true;
0356                         continue;
0357                     }
0358                     else
0359                     {
0360                         // Because of the way the superstructure parsing works there is no
0361                         // 'next line' as it were, the braced code is attached to the current line.
0362                         saveBraced = true;
0363                     }
0364                     break;
0365 
0366                 case (Field::FixedString):
0367                 {
0368                     // Is the string found, and is it starting in the right place?
0369                     int stringPosition  = line.indexOf(QRegExp("\\b"+field.string()+"\\b"));
0370                     if( stringPosition != position || stringPosition == -1 )
0371                     {
0372                         if( !field.compulsory() )
0373                         {
0374                             position = -1;
0375                             // Skip the next field
0376                             ++sdit;
0377                             continue;
0378                         }
0379                         else
0380                         {
0381                             // Otherwise raise an appropriate error
0382                             mistake( MicrobeApp::FixedStringExpected, field.string() );
0383                             errorInLine = true;
0384                             continue;
0385                         }
0386                     }
0387                     else
0388                     {
0389                         position += field.string().length() + 1;
0390                     }
0391                 }
0392                     break;
0393 
0394                 case (Field::Newline):
0395                     // It looks like the best way to handle this is to just actually
0396                     // look at the next line, and see if it begins with an expected fixed
0397                     // string.
0398 
0399                     // Assume there is a next field, it would be silly if there weren't.
0400                     nextField = *(++StatementDefinition::Iterator(sdit));
0401                     if( nextField.type() == Field::FixedString )
0402                     {
0403                         nextStatement = *(++StatementList::Iterator(sit));
0404                         newPosition = nextStatement.text().indexOf(QRegExp("\\b" + nextField.string() + "\\b"));
0405                         if(newPosition != 0)
0406                         {
0407                             // If the next field is optional just carry on as nothing happened,
0408                             // the next line will be processed as a new statement
0409                             if(!nextField.compulsory()) continue;
0410 
0411                         }
0412                         position = 0;
0413                         line = (*(++sit)).text();
0414                         m_currentSourceLine = (*sit).content;
0415                     }
0416 
0417                     break;
0418 
0419                 case (Field::None):
0420                     // Do nothing
0421                     break;
0422             }
0423 
0424             if ( saveToken )
0425                 fieldMap[field.key()] = OutputField( token );
0426 
0427             if ( saveSingleLine )
0428             {
0429                 SourceLineList list;
0430                 list << SourceLineMicrobe( token, nullptr, -1 );
0431                 fieldMap[field.key()] = OutputField( list );
0432             }
0433 
0434             if ( saveBraced )
0435                 fieldMap[field.key()] = OutputField( (*sit).bracedCode );
0436             // If position = -1, we have reached the end of the line.
0437         }
0438 
0439         // See if we got to the end of the line, but not all fields had been
0440         // processed.
0441         if( position != -1  && position <= int(line.length()) )
0442         {
0443             mistake( MicrobeApp::TooManyTokens );
0444             errorInLine = true;
0445         }
0446 
0447         if( errorInLine ) continue;
0448 
0449         // Everything has been parsed up, so send it off for processing.
0450         processStatement( command, fieldMap );
0451 
0452         if( showBracesInSource )
0453             m_code->append(new Instr_sourceCode("}"));
0454     }
0455 
0456     delete m_pPic;
0457     return m_code;
0458 }
0459 
0460 bool Parser::processAssignment(const QString &line)
0461 {
0462     QStringList tokens = Statement::tokenise(line);
0463 
0464     // Have to have at least 3 tokens for an assignment;
0465     if ( tokens.size() < 3 )
0466         return false;
0467 
0468     QString firstToken = tokens[0];
0469 
0470     firstToken = mb->alias(firstToken);
0471     // Well firstly we look to see if it is a known variable.
0472     // These can include 'special' variables such as ports
0473     // For now, the processor subclass generates ports it self
0474     // and puts them in a list for us.
0475 
0476 
0477     // Look for port variables first.
0478     if ( firstToken.contains(".") )
0479     {
0480         PortPin portPin = m_pPic->toPortPin( firstToken );
0481 
0482         // check port is valid
0483         if ( portPin.pin() == -1 )
0484             mistake( MicrobeApp::InvalidPort, firstToken );
0485         // more error checking
0486         if ( tokens[1] != "=" )
0487             mistake( MicrobeApp::UnassignedPin );
0488 
0489         QString state = tokens[2];
0490         if( state == "high" )
0491             m_pPic->Ssetlh( portPin, true );
0492         else if( state == "low" )
0493             m_pPic->Ssetlh( portPin, false );
0494         else
0495             mistake( MicrobeApp::NonHighLowPinState );
0496     }
0497     // no dots, lets try for just a port name
0498     else if( m_pPic->isValidPort( firstToken ) )
0499     {
0500         // error checking
0501         if ( tokens[1] != "=" )
0502             mistake( MicrobeApp::UnassignedPort, tokens[1] );
0503 
0504         Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.indexOf("=")+1));
0505         m_pPic->saveResultToVar( firstToken );
0506     }
0507     else if ( m_pPic->isValidTris( firstToken ) )
0508     {
0509         if( tokens[1] == "=" )
0510         {
0511             Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.indexOf("=")+1));
0512             m_pPic->Stristate(firstToken);
0513         }
0514     }
0515     else
0516     {
0517         // Is there an assignment?
0518         if ( tokens[1] != "=" )
0519             return false;
0520 
0521         if ( !mb->isValidVariableName( firstToken ) )
0522         {
0523             mistake( MicrobeApp::InvalidVariableName, firstToken );
0524             return true;
0525         }
0526 
0527         // Don't care whether or not the variable is new; MicrobeApp will only add it if it
0528         // hasn't been defined yet.
0529         mb->addVariable( Variable( Variable::charType, firstToken ) );
0530 
0531         Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.indexOf("=")+1));
0532 
0533         Variable v = mb->variable( firstToken );
0534         switch ( v.type() )
0535         {
0536             case Variable::charType:
0537                 m_pPic->saveResultToVar( v.name() );
0538                 break;
0539 
0540             case Variable::keypadType:
0541                 mistake( MicrobeApp::ReadOnlyVariable, v.name() );
0542                 break;
0543 
0544             case Variable::sevenSegmentType:
0545                 m_pPic->SsevenSegment( v );
0546                 break;
0547 
0548             case Variable::invalidType:
0549                 // Doesn't happen, but include this case to avoid compiler warnings
0550                 break;
0551         }
0552     }
0553 
0554     return true;
0555 }
0556 
0557 
0558 SourceLineList Parser::getBracedCode( SourceLineList::const_iterator * it, SourceLineList::const_iterator end )
0559 {
0560     // Note: The sourceline list has the braces on separate lines.
0561 
0562     // This function should only be called when the parser comes across a line that is a brace.
0563     assert( (**it).text() == "{" );
0564 
0565     SourceLineList braced;
0566 
0567     // Jump past the first brace
0568     unsigned level = 1;
0569     ++(*it);
0570 
0571     for ( ; *it != end; ++(*it) )
0572     {
0573         if ( (**it).text() == "{" )
0574             level++;
0575 
0576         else if ( (**it).text() == "}" )
0577             level--;
0578 
0579         if ( level == 0 )
0580             return braced;
0581 
0582         braced << **it;
0583     }
0584 
0585     // TODO Error: mismatched bracing
0586     return braced;
0587 }
0588 
0589 
0590 void Parser::processStatement( const QString & name, const OutputFieldMap & fieldMap )
0591 {
0592     // Name is guaranteed to be something known, the calling
0593     // code has taken care of that. Also fieldMap is guaranteed to contain
0594     // all required fields.
0595 
0596     if ( name == "goto" )
0597         m_pPic->Sgoto(fieldMap["label"].string());
0598 
0599     else if ( name == "call" )
0600         m_pPic->Scall(fieldMap["label"].string());
0601 
0602     else if ( name == "while" )
0603         m_pPic->Swhile( parseWithChild(fieldMap["code"].bracedCode() ), fieldMap["expression"].string() );
0604 
0605     else if ( name == "repeat" )
0606         m_pPic->Srepeat( parseWithChild(fieldMap["code"].bracedCode() ), fieldMap["expression"].string() );
0607 
0608     else if ( name == "if" )
0609         m_pPic->Sif(
0610                 parseWithChild(fieldMap["ifCode"].bracedCode() ),
0611                 parseWithChild(fieldMap["elseCode"].bracedCode() ),
0612                 fieldMap["expression"].string() );
0613 
0614     else if ( name == "sub" || name == "subroutine" )
0615     {
0616         if(!m_bPassedEnd)
0617         {
0618             mistake( MicrobeApp::InterruptBeforeEnd );
0619         }
0620         else
0621         {
0622             m_pPic->Ssubroutine( fieldMap["label"].string(), parseWithChild( fieldMap["code"].bracedCode() ) );
0623         }
0624     }
0625     else if( name == "interrupt" )
0626     {
0627         QString interrupt = fieldMap["label"].string();
0628 
0629         if(!m_bPassedEnd)
0630         {
0631             mistake( MicrobeApp::InterruptBeforeEnd );
0632         }
0633         else if( !m_pPic->isValidInterrupt( interrupt ) )
0634         {
0635             mistake( MicrobeApp::InvalidInterrupt );
0636         }
0637         else if ( mb->isInterruptUsed( interrupt ) )
0638         {
0639             mistake( MicrobeApp::InterruptRedefined );
0640         }
0641         else
0642         {
0643             mb->setInterruptUsed( interrupt );
0644             m_pPic->Sinterrupt( interrupt, parseWithChild( fieldMap["code"].bracedCode() ) );
0645         }
0646     }
0647     else if( name == "end" )
0648     {
0649         ///TODO handle end if we are not in the top level
0650         m_bPassedEnd = true;
0651         m_pPic->Send();
0652     }
0653     else if( name == "for" )
0654     {
0655         QString step = fieldMap["stepExpression"].string();
0656         bool stepPositive;
0657 
0658         if( fieldMap["stepExpression"].found() )
0659         {
0660             if(step.left(1) == "+")
0661             {
0662                 stepPositive = true;
0663                 step = step.mid(1).trimmed();
0664             }
0665             else if(step.left(1) == "-")
0666             {
0667                 stepPositive = false;
0668                 step = step.mid(1).trimmed();
0669             }
0670             else stepPositive = true;
0671         }
0672         else
0673         {
0674             step = "1";
0675             stepPositive = true;
0676         }
0677 
0678         QString variable = fieldMap["initExpression"].string().mid(0,fieldMap["initExpression"].string().indexOf("=")).trimmed();
0679         QString endExpr = variable+ " <= " + fieldMap["toExpression"].string().trimmed();
0680 
0681         if( fieldMap["stepExpression"].found() )
0682         {
0683             bool isConstant;
0684             step = processConstant(step,&isConstant);
0685             if( !isConstant )
0686                 mistake( MicrobeApp::NonConstantStep );
0687         }
0688 
0689         SourceLineList tempList;
0690         tempList << SourceLineMicrobe( fieldMap["initExpression"].string(), nullptr, -1 );
0691 
0692         m_pPic->Sfor( parseWithChild( fieldMap["code"].bracedCode() ), parseWithChild( tempList ), endExpr, variable, step, stepPositive );
0693     }
0694     else if( name == "alias" )
0695     {
0696         // It is important to get this the right way round!
0697         // The alias should be the key since two aliases could
0698         // point to the same name.
0699 
0700         QString alias = fieldMap["alias"].string().trimmed();
0701         QString dest = fieldMap["dest"].string().trimmed();
0702 
0703         // Check to see whether or not we've already aliased it...
0704 //      if ( mb->alias(alias) != alias )
0705 //          mistake( MicrobeApp::AliasRedefined );
0706 //      else
0707             mb->addAlias( alias, dest );
0708     }
0709     else if( name == "increment" )
0710     {
0711         QString variableName = fieldMap["variable"].string();
0712 
0713         if ( !mb->isVariableKnown( variableName ) )
0714             mistake( MicrobeApp::UnknownVariable );
0715         else if ( !mb->variable( variableName ).isWritable() )
0716             mistake( MicrobeApp::ReadOnlyVariable, variableName );
0717         else
0718             m_pPic->SincVar( variableName );
0719     }
0720     else if( name == "decrement" )
0721     {
0722         QString variableName = fieldMap["variable"].string();
0723 
0724         if ( !mb->isVariableKnown( variableName ) )
0725             mistake( MicrobeApp::UnknownVariable );
0726         else if ( !mb->variable( variableName ).isWritable() )
0727             mistake( MicrobeApp::ReadOnlyVariable, variableName );
0728         else
0729             m_pPic->SdecVar( variableName );
0730     }
0731     else if( name == "rotateleft" )
0732     {
0733         QString variableName = fieldMap["variable"].string();
0734 
0735         if ( !mb->isVariableKnown( variableName ) )
0736             mistake( MicrobeApp::UnknownVariable );
0737         else if ( !mb->variable( variableName ).isWritable() )
0738             mistake( MicrobeApp::ReadOnlyVariable, variableName );
0739         else
0740             m_pPic->SrotlVar( variableName );
0741     }
0742     else if( name == "rotateright" )
0743     {
0744         QString variableName = fieldMap["variable"].string();
0745 
0746         if ( !mb->isVariableKnown( variableName ) )
0747             mistake( MicrobeApp::UnknownVariable );
0748         else if ( !mb->variable( variableName ).isWritable() )
0749             mistake( MicrobeApp::ReadOnlyVariable, variableName );
0750         else
0751             m_pPic->SrotrVar( variableName );
0752     }
0753     else if( name == "asm" )
0754     {
0755         m_pPic->Sasm( SourceLineMicrobe::toStringList( fieldMap["code"].bracedCode() ).join("\n") );
0756     }
0757     else if( name == "delay" )
0758     {
0759         // This is one of the rare occasions that the number will be bigger than a byte,
0760         // so suppressNumberTooBig must be used
0761         bool isConstant;
0762         QString delay = processConstant(fieldMap["expression"].string(),&isConstant,true);
0763         if (!isConstant)
0764             mistake( MicrobeApp::NonConstantDelay );
0765 //      else m_pPic->Sdelay( fieldMap["expression"].string(), "");
0766         else
0767         {
0768             // TODO We should use the "delay" string returned by processConstant - not the expression (as, e.g. 2*3 won't be ok)
0769             int length_ms = literalToInt( fieldMap["expression"].string() );
0770             if ( length_ms >= 0 )
0771                 m_pPic->Sdelay( length_ms * 1000 ); // Pause the delay length in microseconds
0772             else
0773                 mistake( MicrobeApp::NonConstantDelay );
0774         }
0775     }
0776     else if ( name == "keypad" || name == "sevenseg" )
0777     {
0778         //QStringList pins = QStringList::split( ' ', fieldMap["pinlist"].string() );
0779         QStringList pins = fieldMap["pinlist"].string().split(' ', Qt::SkipEmptyParts);
0780         QString variableName = fieldMap["name"].string();
0781 
0782         if ( mb->isVariableKnown( variableName ) )
0783         {
0784             mistake( MicrobeApp::VariableRedefined, variableName );
0785             return;
0786         }
0787 
0788         PortPinList pinList;
0789 
0790         QStringList::iterator end = pins.end();
0791         for ( QStringList::iterator it = pins.begin(); it != end; ++it )
0792         {
0793             PortPin portPin = m_pPic->toPortPin(*it);
0794             if ( portPin.pin() == -1 )
0795             {
0796                 // Invalid port/pin
0797                 //TODO mistake
0798                 return;
0799             }
0800             pinList << portPin;
0801         }
0802 
0803         if ( name == "keypad" )
0804         {
0805             Variable v( Variable::keypadType, variableName );
0806             v.setPortPinList( pinList );
0807             mb->addVariable( v );
0808         }
0809 
0810         else // name == "sevenseg"
0811         {
0812             if ( pinList.size() != 7 )
0813                 mistake( MicrobeApp::InvalidPinMapSize );
0814             else
0815             {
0816                 Variable v( Variable::sevenSegmentType, variableName );
0817                 v.setPortPinList( pinList );
0818                 mb->addVariable( v );
0819             }
0820         }
0821     }
0822 }
0823 
0824 
0825 void Parser::mistake( MicrobeApp::MistakeType type, const QString & context )
0826 {
0827     mb->compileError( type, context, m_currentSourceLine );
0828 }
0829 
0830 
0831 Statement::Statement() : code(NULL) {
0832 }
0833 
0834 // static function
0835 QStringList Statement::tokenise(const QString &line)
0836 {
0837     QStringList result;
0838     QString current;
0839     int count = 0;
0840 
0841     for(int i = 0; i < int(line.length()); i++)
0842     {
0843         QChar nextChar = line[i];
0844         if( nextChar.isSpace() )
0845         {
0846             if( count > 0 )
0847             {
0848                 result.append(current);
0849                 current = "";
0850                 count = 0;
0851             }
0852         }
0853         else if( nextChar == '=' )
0854         {
0855             if( count > 0 ) result.append(current);
0856             current = "";
0857             count = 0;
0858             result.append("=");
0859         }
0860         else if( nextChar == '{' )
0861         {
0862             if( count > 0 ) result.append(current);
0863             current = "";
0864             count = 0;
0865             result.append("{");
0866         }
0867         else
0868         {
0869             count++;
0870             current.append(nextChar);
0871         }
0872     }
0873     if( count > 0 ) result.append(current);
0874     return result;
0875 }
0876 
0877 int Parser::doArithmetic(int lvalue, int rvalue, Expression::Operation op)
0878 {
0879     switch(op)
0880     {
0881         case Expression::noop: return 0;
0882         case Expression::addition: return lvalue + rvalue;
0883         case Expression::subtraction: return lvalue - rvalue;
0884         case Expression::multiplication: return lvalue * rvalue;
0885         case Expression::division: return lvalue / rvalue;
0886         case Expression::exponent: return lvalue ^ rvalue;
0887         case Expression::equals: return lvalue == rvalue;
0888         case Expression::notequals: return !(lvalue == rvalue);
0889         case Expression::bwand: return lvalue & rvalue;
0890         case Expression::bwor: return lvalue | rvalue;
0891         case Expression::bwxor: return lvalue ^ rvalue;
0892         case Expression::bwnot: return !rvalue;
0893         case Expression::le: return lvalue <= rvalue;
0894         case Expression::ge: return lvalue >= rvalue;
0895         case Expression::lt: return lvalue < rvalue;
0896         case Expression::gt: return lvalue > rvalue;
0897 
0898         case Expression::pin:
0899         case Expression::notpin:
0900         case Expression::function:
0901         case Expression::divbyzero:
0902         case Expression::read_keypad:
0903             // Not applicable actions.
0904             break;
0905     }
0906     return -1;
0907 }
0908 
0909 bool Parser::isLiteral( const QString &text )
0910 {
0911     bool ok;
0912     literalToInt( text, & ok );
0913     return ok;
0914 }
0915 
0916 /*
0917 Literal's in form:
0918 -> 321890
0919 -> 021348
0920 -> 0x3C
0921 -> b'0100110'
0922 -> 0101001b
0923 -> h'43A'
0924 -> 2Ah
0925 
0926 Everything else is non-literal...
0927 */
0928 int Parser::literalToInt( const QString &literal, bool * ok )
0929 {
0930     bool temp;
0931     if ( !ok )
0932         ok = & temp;
0933     *ok = true;
0934 
0935     int value = -1;
0936 
0937     // Note when we use toInt, we don't have to worry about checking
0938     // that literal.mid() is convertible, as toInt returns this in ok anyway.
0939 
0940     // Try binary first, of form b'n...n'
0941     if( literal.left(2) == "b'" && literal.right(1) == "'" )
0942     {
0943         value = literal.mid(2,literal.length() - 3).toInt(ok,2);
0944         return *ok ? value : -1;
0945     }
0946 
0947     // Then try hex of form h'n...n'
0948     if( literal.left(2) == "h'" && literal.right(1) == "'" )
0949     {
0950         value = literal.mid(2,literal.length() - 3).toInt(ok,16);
0951         return *ok ? value : -1;
0952     }
0953 
0954     // otherwise, let QString try and convert it
0955     // base 0 == automatic base guessing
0956     value = literal.toInt( ok, 0 );
0957     return *ok ? value : -1;
0958 }
0959 
0960 
0961 void Parser::compileConditionalExpression( const QString & expression, Code * ifCode, Code * elseCode ) const
0962 {
0963     ///HACK ///TODO this is a little improper, I don't think we should be using the pic that called us...
0964 
0965     Expression( m_pPic, mb, m_currentSourceLine, false ).compileConditional(expression,ifCode,elseCode);
0966 }
0967 
0968 
0969 QString Parser::processConstant(const QString &expression, bool * isConstant, bool suppressNumberTooBig) const
0970 {
0971     return Expression( m_pPic, mb, m_currentSourceLine, suppressNumberTooBig ).processConstant(expression, isConstant);
0972 }
0973 //END class Parser
0974 
0975 
0976 
0977 //BEGIN class Field
0978 Field::Field()
0979 {
0980     m_type = None;
0981     m_compulsory = false;
0982 }
0983 
0984 
0985 Field::Field( Type type, const QString & key )
0986 {
0987     m_type = type;
0988     m_compulsory = false;
0989     m_key = key;
0990 }
0991 
0992 
0993 Field::Field( Type type, const QString & key, const QString & string, bool compulsory )
0994 {
0995     m_type = type;
0996     m_compulsory = compulsory;
0997     m_key = key;
0998     m_string = string;
0999 }
1000 //END class Field
1001 
1002 
1003 
1004 //BEGIN class OutputField
1005 OutputField::OutputField()
1006 {
1007     m_found = false;
1008 }
1009 
1010 
1011 OutputField::OutputField( const SourceLineList & bracedCode )
1012 {
1013     m_bracedCode = bracedCode;
1014     m_found = true;
1015 }
1016 
1017 OutputField::OutputField( const QString & string/*, int lineNumber*/ )
1018 {
1019     m_string = string;
1020     m_found = true;
1021 }
1022 //END class OutputField
1023 
1024 
1025 
1026 #if 0
1027 // Second pass
1028 
1029         else if( firstToken == "include" )
1030         {
1031             // only cope with 'sane' strings a.t.m.
1032             // e.g. include "filename.extenstion"
1033             QString filename = (*sit).content.mid( (*sit).content.find("\"") ).trimmed();
1034             // don't strip whitespace from within quotes as you
1035             // can have filenames composed entirely of spaces (kind of weird)...
1036             // remove quotes.
1037             filename = filename.mid(1);
1038             filename = filename.mid(0,filename.length()-1);
1039             QFile includeFile(filename);
1040             if( includeFile.open(QIODevice::ReadOnly) )
1041             {
1042                 QTextStream stream( &includeFile );
1043                     QStringList includeCode;
1044                 while( !stream.atEnd() )
1045                 {
1046                     includeCode += stream.readLine();
1047                 }
1048                 ///TODO make includes work
1049                 //output += parse(includeCode);
1050                 includeFile.close();
1051                 }
1052                 else
1053                 mistake( MicrobeApp::UnopenableInclude, filename );
1054         }
1055 #endif
1056 
1057