File indexing completed on 2025-04-27 05:16:10
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