parser.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2004-2005 by Daniel Clarke                              *
00003  *   daniel.jc@gmail.com                                                   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020  
00021 #include "btreebase.h"
00022 #include "expression.h"
00023 #include "instruction.h"
00024 #include "parser.h"
00025 #include "pic14.h"
00026 #include "traverser.h"
00027 
00028 #include <cassert>
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 #include <qfile.h>
00032 #include <qregexp.h>
00033 #include <qstring.h>
00034 
00035 #include <iostream>
00036 using namespace std;
00037 
00038 
00039 //BEGIN class Parser
00040 Parser::Parser( Microbe * _mb )
00041 {
00042         m_code = 0;
00043         m_pPic = 0;
00044         mb = _mb;
00045         // Set up statement definitions.
00046         StatementDefinition definition;
00047         
00048         definition.append( Field(Field::Label, "label") );
00049         m_definitionMap["goto"] = definition;
00050         definition.clear();
00051         
00052         definition.append( Field(Field::Label, "label") );
00053         m_definitionMap["call"] = definition;
00054         definition.clear();
00055         
00056         definition.append( Field(Field::Expression, "expression") );
00057         definition.append( Field(Field::Code, "code") );
00058         m_definitionMap["while"] = definition;
00059         definition.clear();
00060         
00061         m_definitionMap["end"] = definition;
00062         definition.clear();
00063         
00064         definition.append( Field(Field::Label, "label") );
00065         definition.append( Field(Field::Code, "code") );
00066         // For backwards compataibility
00067         m_definitionMap["sub"] = definition;
00068         m_definitionMap["subroutine"] = definition;
00069         definition.clear();
00070         
00071         definition.append( Field(Field::Label, "label") );
00072         definition.append( Field(Field::Code, "code") );
00073         m_definitionMap["interrupt"] = definition;
00074         definition.clear();
00075 
00076         definition.append( Field(Field::Label, "alias") );
00077         definition.append( Field(Field::Label, "dest") );
00078         m_definitionMap["alias"] = definition;
00079         definition.clear();
00080         
00081         definition.append( Field(Field::Expression, "expression") );
00082         definition.append( Field(Field::FixedString, 0, "then", true) );
00083         definition.append( Field(Field::Code, "ifCode") );
00084         definition.append( Field(Field::Newline) );
00085         definition.append( Field(Field::FixedString, 0, "else", false) );
00086         definition.append( Field(Field::Code, "elseCode") );
00087         m_definitionMap["if"] = definition;
00088         definition.clear();
00089         
00090         definition.append( Field(Field::Expression, "initExpression") );
00091         definition.append( Field(Field::FixedString, 0, "to", true) );
00092         definition.append( Field(Field::Expression, "toExpression") );
00093         definition.append( Field(Field::FixedString, 0, "step", false) );
00094         definition.append( Field(Field::Expression, "stepExpression") );
00095         definition.append( Field(Field::Code, "code") );
00096         m_definitionMap["for"] = definition;
00097         definition.clear();
00098         
00099         definition.append( Field(Field::Variable, "variable") );
00100         m_definitionMap["decrement"] = definition;
00101         definition.clear();
00102         
00103         definition.append( Field(Field::Variable, "variable") );
00104         m_definitionMap["increment"] = definition;
00105         definition.clear();
00106         
00107         definition.append( Field(Field::Variable, "variable") );
00108         m_definitionMap["rotateleft"] = definition;
00109         definition.clear();
00110         
00111         definition.append( Field(Field::Variable, "variable") );
00112         m_definitionMap["rotateright"] = definition;
00113         definition.clear();
00114         
00115         definition.append( Field(Field::Code, "code") );
00116         m_definitionMap["asm"] = definition;
00117         definition.clear();
00118         
00119         definition.append( Field(Field::Expression, "expression") );
00120         m_definitionMap["delay"] = definition;
00121         definition.clear();
00122         
00123         definition.append( Field(Field::Code, "code") );
00124         definition.append( Field(Field::Newline) );
00125         definition.append( Field(Field::FixedString, 0, "until", true) );
00126         definition.append( Field(Field::Expression, "expression") );
00127         m_definitionMap["repeat"] = definition;
00128         definition.clear();
00129         
00130         definition.append( Field(Field::Name, "name") );
00131         definition.append( Field(Field::PinList, "pinlist") );
00132         m_definitionMap["sevenseg"] = definition;
00133         definition.clear();
00134         
00135         definition.append( Field(Field::Name, "name") );
00136         definition.append( Field(Field::PinList, "pinlist") );
00137         m_definitionMap["keypad"] = definition;
00138         definition.clear();
00139 }
00140 
00141 Parser::~Parser()
00142 {
00143 }
00144 
00145 Parser* Parser::createChildParser()
00146 {
00147         Parser * parser = new Parser( mb );
00148         
00149         return parser;
00150 }
00151 
00152 
00153 Code * Parser::parseWithChild( const SourceLineList & lines )
00154 {
00155         Parser *p = createChildParser();
00156         Code *code = p->parse(lines);
00157         delete p;
00158         return code;
00159 }
00160 
00161 Code * Parser::parse( const SourceLineList & lines )
00162 {
00163         StatementList sList;
00164         m_pPic = mb->makePic();
00165         m_code = new Code();
00166         m_pPic->setCode( m_code );
00167         m_pPic->setParser(this);
00168         m_bPassedEnd = false;
00169         
00170         /* First pass
00171            ==========
00172            
00173            Here we go through the code making each line into a statement object,
00174            looking out for braced code as we go, if we find it then we put then
00175            we make attach the braced code to the statment.
00176         */   
00177 
00178         SourceLineList::const_iterator end = lines.end();
00179         for ( SourceLineList::const_iterator slit = lines.begin(); slit != end; ++slit) {
00180                 Statement s;
00181                 s.content = *slit;
00182 
00183                 // Check to see if the line after next is a brace
00184                 SourceLineList::const_iterator previous = slit;
00185                 if ( (++slit != end) && (*slit).text() == "{" )
00186                         s.bracedCode = getBracedCode( & slit, end );
00187                 else slit = previous;
00188 
00189                 if(!s.text().isEmpty()) sList.append(s);
00190         }
00191 
00192         mb->resetDest();
00193 
00194         for(StatementList::Iterator sit = sList.begin(); sit != sList.end(); ++sit) {
00195                 m_currentSourceLine = (*sit).content;
00196 
00197                 QString line = (*sit).text();
00198 
00199                 QString command; // e.g. "delay", "for", "subroutine", "increment", etc
00200                 {
00201                         int spacepos = line.find(' ');
00202                         if ( spacepos >= 0 ) command = line.left( spacepos );
00203                         else command = line;
00204                 }
00205                 OutputFieldMap fieldMap;
00206 
00207                 if ( (*sit).content.line() >= 0 )
00208                         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() ) ));
00209                 bool showBracesInSource = (*sit).hasBracedCode();
00210                 if ( showBracesInSource )
00211                         m_code->append(new Instr_sourceCode("{"));
00212 
00213                 // Use the first token in the line to look up the statement type
00214                 DefinitionMap::Iterator dmit = m_definitionMap.find(command);
00215                 if(dmit == m_definitionMap.end()) {
00216                         if(!processAssignment( (*sit).text())) {
00217                                 // Not an assignement, maybe a label
00218                                 if( (*sit).isLabel() ) {
00219                                         QString label = (*sit).text().left( (*sit).text().length() - 1 );
00221                                         m_pPic->Slabel( label );
00222                                 } else mistake( Microbe::Microbe::UnknownStatement );
00223                         }
00224 
00225                         continue; // Give up on the current statement
00226                 }
00227                 StatementDefinition definition = dmit.data();
00228 
00229                 // Start at the first white space character following the statement name
00230                 int newPosition = 0;
00231                 int position = command.length() + 1;
00232 
00233                 // Temporaries for use inside the switch
00234                 Field nextField;
00235                 Statement nextStatement;
00236 
00237                 bool errorInLine = false;
00238                 bool finishLine = false;
00239 
00240                 for(StatementDefinition::Iterator sdit = definition.begin(); sdit != definition.end(); ++sdit) {
00241                         // If there is an error, or we have finished the statement,
00242                         // the stop. If we are at the end of a line in a multiline, then
00243                         // break to fall through to the next line
00244                         if( errorInLine || finishLine) break;
00245 
00246                         Field field = (*sdit);
00247                         QString token;
00248 
00249                         bool saveToken = false;
00250                         bool saveBraced = false;
00251                         bool saveSingleLine = false;
00252 
00253                         switch(field.type()) {
00254                                 case (Field::Label):
00255                                 case (Field::Variable):
00256                                 case (Field::Name):
00257                                 {
00258                                         newPosition = line.find( ' ', position );
00259                                         if(position == newPosition) {
00260                                                 newPosition = -1;
00261                                                 token = line.mid(position);
00262                                         } else token = line.mid(position, newPosition - position);
00263                                         if( token.isEmpty() ) {
00264                                                 if(field.type() == Field::Label)
00265                                                         mistake( Microbe::Microbe::LabelExpected );
00266                                                 else if (field.type() == Field::Variable)
00267                                                         mistake( Microbe::VariableExpected );
00268                                                 else // field.type() == Field::Name
00269                                                         mistake( Microbe::NameExpected );
00270                                                 errorInLine = true;
00271                                                 continue;
00272                                         }
00273                                         position = newPosition;
00274                                         saveToken = true;
00275                                         break;
00276                                 }
00277 
00278                                 case (Field::Expression):
00279                                 {
00280                                         // This is slightly different, as there is nothing
00281                                         // in particular that delimits an expression, we just have to
00282                                         // look at what comes next and hope we can use that.
00283                                         StatementDefinition::Iterator it(sdit);
00284                                         ++it;
00285                                         if( it != definition.end() ) {
00286                                                 nextField = (*it);
00287                                                 if(nextField.type() == Field::FixedString) 
00288                                                         newPosition = line.find(QRegExp("\\b" + nextField.string() + "\\b"));
00289                                                 // Although code is not neccessarily braced, after an expression it is the only
00290                                                 // sensilbe way to have it.
00291                                                 else if(nextField.type() == Field::Code) {
00292                                                         newPosition = line.find("{");
00293                                                         if(newPosition == -1) newPosition = line.length() + 1;
00294                                                 } else if(nextField.type() == Field::Newline)
00295                                                         newPosition = line.length()+1;
00296                                                 else kdDebug() << "Bad statement definition - awkward field type after expression";
00297                                         } else newPosition = line.length() + 1;
00298 
00299                                         if(newPosition == -1) {
00300                                                 // Something was missing, we'll just play along for now,
00301                                                 // the next iteration will catch whatever was supposed to be there
00302                                         }
00303                                         token = line.mid(position, newPosition - position);
00304                                         position = newPosition;
00305                                         saveToken = true;
00306                                 }
00307                                         break;
00308 
00309                                 case (Field::PinList):
00310                                 {
00311                                         // For now, just assume that the list of pins will continue to the end of the tokens.
00312                                         // (we could check until we come across a non-pin, but no command has that format at
00313                                         // the moment).
00314                                         
00315                                         token = line.mid( position + 1 );
00316                                         position = line.length() + 1;
00317 
00318                                         if ( token.isEmpty() )
00319                                                 mistake( Microbe::PinListExpected );
00320                                         else saveToken = true;
00321 
00322                                         break;
00323                                 }
00324                                         
00325                                 case (Field::Code):
00326                                         if ( !(*sit).hasBracedCode() ) {
00327                                                 saveSingleLine = true;
00328                                                 token = line.mid(position);
00329                                                 position = line.length() + 1;
00330                                         } else if( position != -1  && position <= int(line.length()) )
00331                                         {
00332                                                 mistake( Microbe::UnexpectedStatementBeforeBracket );
00333                                                 errorInLine = true;
00334                                                 continue;
00335                                         } else {
00336                                                 // Because of the way the superstructure parsing works there is no
00337                                                 // 'next line' as it were, the braced code is attached to the current line.
00338                                                 saveBraced = true;
00339                                         }
00340                                         break;
00341                                         
00342                                 case (Field::FixedString):
00343                                 {
00344                                         // Is the string found, and is it starting in the right place?
00345                                         int stringPosition  = line.find(QRegExp("\\b"+field.string()+"\\b"));
00346                                         if( stringPosition != position || stringPosition == -1 ) {
00347                                                 if( !field.compulsory() )
00348                                                 {
00349                                                         position = -1;
00350                                                         // Skip the next field
00351                                                         ++sdit;
00352                                                         continue;
00353                                                 } else {
00354                                                         // Otherwise raise an appropriate error
00355                                                         mistake( Microbe::FixedStringExpected, field.string() );
00356                                                         errorInLine = true;
00357                                                         continue;
00358                                                 }
00359                                         } else {
00360                                                 position += field.string().length() + 1;
00361                                         }
00362                                 }
00363                                         break;
00364                                         
00365                                 case (Field::Newline):
00366                                         // It looks like the best way to handle this is to just actually
00367                                         // look at the next line, and see if it begins with an expected fixed
00368                                         // string.
00369                                         
00370                                         // Assume there is a next field, it would be silly if there weren't.
00371                                         nextField = *(++StatementDefinition::Iterator(sdit));
00372                                         if( nextField.type() == Field::FixedString )
00373                                         {
00374                                                 nextStatement = *(++StatementList::Iterator(sit));
00375                                                 newPosition = nextStatement.text().find(QRegExp("\\b" + nextField.string() + "\\b"));
00376                                                 if(newPosition != 0)
00377                                                 {
00378                                                         // If the next field is optional just carry on as nothing happened,
00379                                                         // the next line will be processed as a new statement
00380                                                         if(!nextField.compulsory()) continue;
00381                                                         
00382                                                 }
00383                                                 position = 0;
00384                                                 line = (*(++sit)).text();
00385                                                 m_currentSourceLine = (*sit).content;
00386                                         }
00387                                         
00388                                         break;
00389                                         
00390                                 case (Field::None):
00391                                         // Do nothing
00392                                         break;
00393                         }
00394 
00395                         if ( saveToken )
00396                                 fieldMap[field.key()] = OutputField( token );
00397 
00398                         if(saveSingleLine) {
00399                                 SourceLineList list;
00400                                 list << SourceLine( token, 0, -1 );
00401                                 fieldMap[field.key()] = OutputField( list );
00402                         }
00403                         
00404                         if(saveBraced)
00405                                 fieldMap[field.key()] = OutputField( (*sit).bracedCode );
00406                         // If position = -1, we have reached the end of the line.
00407                 }
00408                 
00409                 // See if we got to the end of the line, but not all fields had been
00410                 // processed.
00411                 if(position != -1  && position <= int(line.length())) {
00412                         mistake( Microbe::TooManyTokens );
00413                         errorInLine = true;
00414                 }
00415 
00416                 if(errorInLine) continue;
00417 
00418                 // Everything has been parsed up, so send it off for processing.
00419                 processStatement( command, fieldMap );
00420 
00421                 if(showBracesInSource)
00422                         m_code->append(new Instr_sourceCode("}"));
00423         }
00424         
00425         delete m_pPic;
00426         m_pPic = 0;
00427         return m_code;
00428 }
00429 
00430 bool Parser::processAssignment(const QString &line)
00431 {
00432         QStringList tokens = Statement::tokenise(line);
00433         
00434         // Have to have at least 3 tokens for an assignment;
00435         if(tokens.size() < 3) return false;
00436 
00437         QString firstToken = tokens[0];
00438 
00439         firstToken = mb->alias(firstToken);
00440         // Well firstly we look to see if it is a known variable. 
00441         // These can include 'special' variables such as ports
00442         // For now, the processor subclass generates ports it self
00443         // and puts them in a list for us.
00444 
00445         // Look for port variables first.
00446         if ( firstToken.contains(".") ) {
00447                 PortPin portPin = m_pPic->toPortPin( firstToken );
00448 
00449                 // check port is valid
00450                 if ( portPin.pin() == -1 )
00451                         mistake( Microbe::InvalidPort, firstToken );
00452                 // more error checking
00453                 if ( tokens[1] != "=" )
00454                         mistake( Microbe::UnassignedPin );
00455 
00456                 QString state = tokens[2];
00457                 if( state == "high" )
00458                         m_pPic->Ssetlh( portPin, true );
00459                 else if( state == "low" )
00460                         m_pPic->Ssetlh( portPin, false );
00461                 else mistake( Microbe::NonHighLowPinState );
00462         }
00463         // no dots, lets try for just a port name
00464         else if(m_pPic->isValidPort(firstToken)) {
00465                 // error checking
00466                 if ( tokens[1] != "=" )
00467                         mistake( Microbe::UnassignedPort, tokens[1] );
00468 
00469                 Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.find("=")+1));
00470                 m_pPic->saveResultToVar( firstToken );
00471         } else if(m_pPic->isValidTris( firstToken)) {
00472                 if(tokens[1] == "=") {
00473                         Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.find("=")+1));
00474                         m_pPic->Stristate(firstToken);
00475                 }
00476         } else {
00477                 // Is there an assignment?
00478                 if(tokens[1] != "=") return false;
00479 
00480                 if(!mb->isValidVariableName(firstToken)) {
00481                         mistake( Microbe::InvalidVariableName, firstToken );
00482                         return true;
00483                 }
00484 
00485                 // Don't care whether or not the variable is new; Microbe will only add it if it
00486                 // hasn't been defined yet.
00487                 mb->addVariable( Variable( Variable::charType, firstToken ) );
00488 
00489                 Expression( m_pPic, mb, m_currentSourceLine, false ).compileExpression(line.mid(line.find("=")+1));
00490 
00491                 Variable v = mb->variable( firstToken );
00492                 switch(v.type()) {
00493                         case Variable::charType:
00494                                 m_pPic->saveResultToVar( v.name() );
00495                                 break;
00496                                 
00497                         case Variable::keypadType:
00498                                 mistake( Microbe::ReadOnlyVariable, v.name() );
00499                                 break;
00500                                 
00501                         case Variable::sevenSegmentType:
00502                                 m_pPic->SsevenSegment( v );
00503                                 break;
00504                                 
00505                         case Variable::invalidType:
00506                                 // Doesn't happen, but include this case to avoid compiler warnings
00507                                 break;
00508                 }
00509         }
00510 
00511         return true;
00512 }
00513 
00514 SourceLineList Parser::getBracedCode( SourceLineList::const_iterator * it, SourceLineList::const_iterator end )
00515 {
00516         // Note: The sourceline list has the braces on separate lines.
00517 
00518         // This function should only be called when the parser comes across a line that is a brace.
00519         assert( (**it).text() == "{" );
00520 
00521         SourceLineList braced;
00522 
00523         // Jump past the first brace
00524         unsigned level = 1;
00525         ++(*it);
00526 
00527         for( ; *it != end; ++(*it)) {
00528                 if ( (**it).text() == "{" ) level++;
00529                 else if ( (**it).text() == "}" )
00530                         level--;
00531 
00532                 if(level == 0)return braced;
00533                 braced << **it;
00534         }
00535 
00536         // TODO Error: mismatched bracing
00537         return braced;
00538 }
00539 
00540 void Parser::processStatement( const QString & name, const OutputFieldMap & fieldMap )
00541 {
00542         // Name is guaranteed to be something known, the calling
00543         // code has taken care of that. Also fieldMap is guaranteed to contain
00544         // all required fields.
00545 
00546         if ( name == "goto" )
00547                 m_pPic->Sgoto(fieldMap["label"].string());
00548         else if ( name == "call" )
00549                 m_pPic->Scall(fieldMap["label"].string());
00550         else if ( name == "while" )
00551                 m_pPic->Swhile( parseWithChild(fieldMap["code"].bracedCode() ), fieldMap["expression"].string() );
00552         else if ( name == "repeat" )
00553                 m_pPic->Srepeat( parseWithChild(fieldMap["code"].bracedCode() ), fieldMap["expression"].string() );
00554         else if ( name == "if" )
00555                 m_pPic->Sif(
00556                                 parseWithChild(fieldMap["ifCode"].bracedCode() ),
00557                                 parseWithChild(fieldMap["elseCode"].bracedCode() ),
00558                                 fieldMap["expression"].string() );
00559         else if(name == "sub" || name == "subroutine" ) {
00560                 if(!m_bPassedEnd) {
00561                         mistake( Microbe::InterruptBeforeEnd );
00562                 } else {
00563                         m_pPic->Ssubroutine( fieldMap["label"].string(), parseWithChild( fieldMap["code"].bracedCode() ) );
00564                 }
00565         } else if( name == "interrupt" ) {
00566                 QString interrupt = fieldMap["label"].string();
00567                 
00568                 if(!m_bPassedEnd)
00569                 {
00570                         mistake( Microbe::InterruptBeforeEnd );
00571                 }
00572                 else if( !m_pPic->isValidInterrupt( interrupt ) )
00573                 {
00574                         mistake( Microbe::InvalidInterrupt );
00575                 }
00576                 else if ( mb->isInterruptUsed( interrupt ) )
00577                 {
00578                         mistake( Microbe::InterruptRedefined );
00579                 } else {
00580                         mb->setInterruptUsed( interrupt );
00581                         m_pPic->Sinterrupt( interrupt, parseWithChild( fieldMap["code"].bracedCode() ) );
00582                 }
00583         } else if( name == "end" ) {
00585                 m_bPassedEnd = true;
00586                 m_pPic->Send();
00587         } else if( name == "for" ) {
00588                 QString step = fieldMap["stepExpression"].string();
00589                 bool stepPositive;
00590 
00591                 if(fieldMap["stepExpression"].found()) {
00592                         if(step.left(1) == "+") {
00593                                 stepPositive = true;
00594                                 step = step.mid(1).stripWhiteSpace();
00595                         } else if(step.left(1) == "-") {
00596                                 stepPositive = false;
00597                                 step = step.mid(1).stripWhiteSpace();
00598                         } else stepPositive = true;
00599                 } else {
00600                         step = "1";
00601                         stepPositive = true;
00602                 }
00603 
00604                 QString variable = fieldMap["initExpression"].string().mid(0,fieldMap["initExpression"].string().find("=")).stripWhiteSpace();
00605                 QString endExpr = variable+ " <= " + fieldMap["toExpression"].string().stripWhiteSpace();
00606 
00607                 if(fieldMap["stepExpression"].found()) {
00608                         bool isConstant;
00609                         step = processConstant(step,&isConstant);
00610                         if( !isConstant )
00611                                 mistake( Microbe::NonConstantStep );
00612                 }
00613 
00614                 SourceLineList tempList;
00615                 tempList << SourceLine( fieldMap["initExpression"].string(), 0, -1 );
00616                 
00617                 m_pPic->Sfor( parseWithChild( fieldMap["code"].bracedCode() ), parseWithChild( tempList ), endExpr, variable, step, stepPositive );
00618         } else if( name == "alias" ) {
00619                 // It is important to get this the right way round!
00620                 // The alias should be the key since two aliases could
00621                 // point to the same name.
00622         
00623                 QString alias = fieldMap["alias"].string().stripWhiteSpace(); 
00624                 QString dest = fieldMap["dest"].string().stripWhiteSpace();
00625                 
00626                 // Check to see whether or not we've already aliased it...
00627 //              if ( mb->alias(alias) != alias )
00628 //                      mistake( Microbe::AliasRedefined );
00629 //              else
00630                         mb->addAlias( alias, dest );
00631         } else if(name == "increment") {
00632                 QString variableName = fieldMap["variable"].string();
00633                 
00634                 if ( !mb->isVariableKnown( variableName ) )
00635                         mistake( Microbe::UnknownVariable );
00636                 else if ( !mb->variable( variableName ).isWritable() )
00637                         mistake( Microbe::ReadOnlyVariable, variableName );
00638                 else
00639                         m_pPic->SincVar( variableName );
00640         } else if( name == "decrement" ) {
00641                 QString variableName = fieldMap["variable"].string();
00642                 
00643                 if ( !mb->isVariableKnown( variableName ) )
00644                         mistake( Microbe::UnknownVariable );
00645                 else if ( !mb->variable( variableName ).isWritable() )
00646                         mistake( Microbe::ReadOnlyVariable, variableName );
00647                 else
00648                         m_pPic->SdecVar( variableName );
00649         } else if( name == "rotateleft" ) {
00650                 QString variableName = fieldMap["variable"].string();
00651                 
00652                 if ( !mb->isVariableKnown( variableName ) )
00653                         mistake( Microbe::UnknownVariable );
00654                 else if ( !mb->variable( variableName ).isWritable() )
00655                         mistake( Microbe::ReadOnlyVariable, variableName );
00656                 else
00657                         m_pPic->SrotlVar( variableName );
00658         } else if( name == "rotateright" ) {
00659                 QString variableName = fieldMap["variable"].string();
00660                 
00661                 if ( !mb->isVariableKnown( variableName ) )
00662                         mistake( Microbe::UnknownVariable );
00663                 else if ( !mb->variable( variableName ).isWritable() )
00664                         mistake( Microbe::ReadOnlyVariable, variableName );
00665                 else
00666                         m_pPic->SrotrVar( variableName );
00667         } else if( name == "asm" ) {
00668                 m_pPic->Sasm( SourceLine::toStringList( fieldMap["code"].bracedCode() ).join("\n") );
00669         } else if( name == "delay" ) {
00670                 // This is one of the rare occasions that the number will be bigger than a byte,
00671                 // so suppressNumberTooBig must be used
00672                 bool isConstant;
00673                 QString delay = processConstant(fieldMap["expression"].string(),&isConstant,true);
00674                 if (!isConstant)
00675                         mistake( Microbe::NonConstantDelay );
00676 //              else m_pPic->Sdelay( fieldMap["expression"].string(), "");
00677                 else {
00678                         // TODO We should use the "delay" string returned by processConstant - not the expression (as, e.g. 2*3 won't be ok)
00679                         int length_ms = literalToInt( fieldMap["expression"].string() );
00680                         if ( length_ms >= 0 )
00681                                 m_pPic->Sdelay( length_ms * 1000 ); // Pause the delay length in microseconds
00682                         else mistake( Microbe::NonConstantDelay );
00683                 }
00684         } else if ( name == "keypad" || name == "sevenseg" ) {
00685                 QStringList pins = QStringList::split( ' ', fieldMap["pinlist"].string() );
00686                 QString variableName = fieldMap["name"].string();
00687                 
00688                 if ( mb->isVariableKnown( variableName ) ) {
00689                         mistake( Microbe::VariableRedefined, variableName );
00690                         return;
00691                 }
00692 
00693                 PortPinList pinList;
00694 
00695                 QStringList::iterator end = pins.end();
00696                 for(QStringList::iterator it = pins.begin(); it != end; ++it) {
00697                         PortPin portPin = m_pPic->toPortPin(*it);
00698                         if ( portPin.pin() == -1 ) {
00699                                 // Invalid port/pin
00700                                 //TODO mistake
00701                                 return;
00702                         }
00703                         pinList << portPin;
00704                 }
00705                 
00706                 if ( name == "keypad" ) {
00707                         Variable v( Variable::keypadType, variableName );
00708                         v.setPortPinList( pinList );
00709                         mb->addVariable( v );
00710                 } else // name == "sevenseg"
00711                 {
00712                         if ( pinList.size() != 7 )
00713                                 mistake( Microbe::InvalidPinMapSize );
00714                         else {
00715                                 Variable v( Variable::sevenSegmentType, variableName );
00716                                 v.setPortPinList( pinList );
00717                                 mb->addVariable( v );
00718                         }
00719                 }
00720         }
00721 }
00722 
00723 void Parser::mistake( Microbe::MistakeType type, const QString & context )
00724 {
00725         mb->compileError( type, context, m_currentSourceLine );
00726 }
00727 
00728 // static function
00729 QStringList Statement::tokenise(const QString &line)
00730 {
00731         QStringList result;
00732         QString current;
00733         int count = 0;
00734         
00735         for(int i = 0; i < int(line.length()); i++) {
00736                 QChar nextChar = line[i];
00737                 if( nextChar.isSpace() ) {
00738                         if( count > 0 ) {
00739                                 result.append(current);
00740                                 current = "";
00741                                 count = 0;
00742                         }
00743                 } else if(nextChar == '=') {
00744                         if( count > 0 ) result.append(current);
00745                         current = "";
00746                         count = 0;
00747                         result.append("=");
00748                 } else if(nextChar == '{') {
00749                         if( count > 0 ) result.append(current);
00750                         current = "";
00751                         count = 0;
00752                         result.append("{");
00753                 } else {
00754                         count++;
00755                         current.append(nextChar);
00756                 }
00757         }
00758         if( count > 0 ) result.append(current);
00759         return result;
00760 }
00761 
00762 int Parser::doArithmetic(int lvalue, int rvalue, Expression::Operation op)
00763 {
00764         switch(op) {
00765                 case Expression::noop: return 0;
00766                 case Expression::addition: return lvalue + rvalue;
00767                 case Expression::subtraction: return lvalue - rvalue;
00768                 case Expression::multiplication: return lvalue * rvalue;
00769                 case Expression::division: return lvalue / rvalue;
00770                 case Expression::exponent: return lvalue ^ rvalue;
00771                 case Expression::equals: return lvalue == rvalue;
00772                 case Expression::notequals: return !(lvalue == rvalue);
00773                 case Expression::bwand: return lvalue & rvalue;
00774                 case Expression::bwor: return lvalue | rvalue;
00775                 case Expression::bwxor: return lvalue ^ rvalue;
00776                 case Expression::bwnot: return !rvalue;
00777                 case Expression::le: return lvalue <= rvalue;
00778                 case Expression::ge: return lvalue >= rvalue;
00779                 case Expression::lt: return lvalue < rvalue;
00780                 case Expression::gt: return lvalue > rvalue;
00781                 
00782                 case Expression::pin:
00783                 case Expression::notpin:
00784                 case Expression::function:
00785                 case Expression::divbyzero:
00786                 case Expression::read_keypad:
00787                         // Not applicable actions.
00788                         break;
00789         }
00790         return -1;
00791 }
00792 
00793 bool Parser::isLiteral( const QString &text )
00794 {
00795         bool ok;
00796         literalToInt( text, & ok );
00797         return ok;
00798 }
00799 
00800 /*
00801 Literal's in form:
00802 -> 321890
00803 -> 021348
00804 -> 0x3C
00805 -> b'0100110'
00806 -> 0101001b
00807 -> h'43A'
00808 -> 2Ah
00809 
00810 Everything else is non-literal...
00811 */
00812 int Parser::literalToInt(const QString &literal, bool *ok )
00813 {
00814         bool temp;
00815         if ( !ok ) ok = &temp;
00816 
00817         *ok = true;
00818 
00819         int value = -1;
00820 
00821         // Note when we use toInt, we don't have to worry about checking 
00822         // that literal.mid() is convertible, as toInt returns this in ok anyway.
00823 
00824         // Try binary first, of form b'n...n'
00825         if( literal.left(2) == "b'" && literal.right(1) == "'" ) {
00826                 value = literal.mid(2,literal.length() - 3).toInt(ok,2);
00827                 return *ok ? value : -1;
00828         }
00829                 
00830         // Then try hex of form h'n...n'
00831         if( literal.left(2) == "h'" && literal.right(1) == "'" ) {
00832                 value = literal.mid(2,literal.length() - 3).toInt(ok,16);
00833                 return *ok ? value : -1;
00834         }
00835 
00836         // otherwise, let QString try and convert it
00837         // base 0 == automatic base guessing
00838         value = literal.toInt( ok, 0 );
00839         return *ok ? value : -1;
00840 }
00841 
00842 void Parser::compileConditionalExpression( const QString & expression, Code * ifCode, Code * elseCode ) const
00843 {
00845 
00846         Expression( m_pPic, mb, m_currentSourceLine, false ).compileConditional(expression,ifCode,elseCode);
00847 }
00848 
00849 QString Parser::processConstant(const QString &expression, bool * isConstant, bool suppressNumberTooBig) const
00850 {
00851         return Expression( m_pPic, mb, m_currentSourceLine, suppressNumberTooBig ).processConstant(expression, isConstant);
00852 }
00853 //END class Parser
00854 
00855 //BEGIN class Field
00856 Field::Field()
00857 {
00858         m_type = None;
00859         m_compulsory = false;
00860 }
00861 
00862 Field::Field( Type type, const QString & key )
00863 {
00864         m_type = type;
00865         m_compulsory = false;
00866         m_key = key;
00867 }
00868 
00869 Field::Field( Type type, const QString & key, const QString & string, bool compulsory )
00870 {
00871         m_type = type;
00872         m_compulsory = compulsory;
00873         m_key = key;
00874         m_string = string;
00875 }
00876 //END class Field
00877 
00878 //BEGIN class OutputField
00879 OutputField::OutputField()
00880 {
00881         m_found = false;
00882 }
00883 
00884 OutputField::OutputField( const SourceLineList & bracedCode )
00885 {
00886         m_bracedCode = bracedCode;
00887         m_found = true;
00888 }
00889 
00890 OutputField::OutputField( const QString & string/*, int lineNumber*/ )
00891 {
00892         m_string = string;
00893         m_found = true;
00894 }
00895 //END class OutputField
00896 
00897 #if 0
00898 // Second pass
00899 
00900                 else if( firstToken == "include" )
00901                 {
00902                         // only cope with 'sane' strings a.t.m.
00903                         // e.g. include "filename.extenstion"
00904                         QString filename = (*sit).content.mid( (*sit).content.find("\"") ).stripWhiteSpace();
00905                         // don't strip whitespace from within quotes as you
00906                         // can have filenames composed entirely of spaces (kind of weird)...
00907                         // remove quotes.
00908                         filename = filename.mid(1); 
00909                         filename = filename.mid(0,filename.length()-1);
00910                         QFile includeFile(filename);
00911                         if( includeFile.open(IO_ReadOnly) )
00912                         {
00913                                 QTextStream stream( &includeFile );
00914                                 QStringList includeCode;
00915                                 while( !stream.atEnd() )
00916                                 {
00917                                         includeCode += stream.readLine();
00918                                 }
00920                                 //output += parse(includeCode);
00921                                 includeFile.close();
00922                         }
00923                         else
00924                         mistake( Microbe::UnopenableInclude, filename );
00925                 }               
00926 #endif
00927 

Generated on Tue May 8 17:05:31 2007 for KTechLab by  doxygen 1.5.1