File indexing completed on 2025-02-16 08:26:49
0001 /*************************************************************************** 0002 * Copyright (C) 2004-2005 by Daniel Clarke daniel.jc@gmail.com * 0003 * Copyright (C) 2005 by David Saxton * 0004 * * 0005 * 24-04-2007 * 0006 * Modified to add pic 16f877,16f627 and 16f628 * 0007 * by george john george@space-kerala.org * 0008 * supported by SPACE www.space-kerala.org * 0009 * * 0010 * This program is free software; you can redistribute it and/or modify * 0011 * it under the terms of the GNU General Public License as published by * 0012 * the Free Software Foundation; either version 2 of the License, or * 0013 * (at your option) any later version. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program; if not, write to the * 0022 * Free Software Foundation, Inc., * 0023 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0024 ***************************************************************************/ 0025 0026 #include "instruction.h" 0027 #include "microbe.h" 0028 #include "parser.h" 0029 #include "optimizer.h" 0030 #include "pic14.h" 0031 0032 #include <KLocalizedString> 0033 0034 #include <QDebug> 0035 #include <QFile> 0036 0037 #include <iostream> 0038 using namespace std; 0039 0040 0041 //BEGIN class MicrobeApp 0042 MicrobeApp::MicrobeApp() 0043 { 0044 m_maxDelaySubroutine = PIC14::Delay_None; 0045 m_dest = 0; 0046 m_uniqueLabel = 0; 0047 0048 // Hardwired constants 0049 m_aliasList["true"] = "1"; 0050 m_aliasList["false"] = "0"; 0051 // Things starting with b are reserved by gpasm (for binary numbers) 0052 m_aliasList["b"] = "_b"; 0053 0054 //BEGIN Keypad values 0055 int bv[4][6] = { 0056 { 1, 2, 3, 10, 14, 18 }, 0057 { 4, 5, 6, 11, 15, 19 }, 0058 { 7, 8, 9, 12, 16, 20 }, 0059 { 253, 0, 254, 13, 17, 21 } }; 0060 0061 for ( unsigned row = 0; row < 4; ++row ) 0062 { 0063 for ( unsigned col = 0; col < 6; ++col ) 0064 { 0065 m_aliasList[ QString("Keypad_%1_%2").arg(row+1).arg(col+1) ] = QString::number( bv[row][col] ); 0066 } 0067 } 0068 0069 m_aliasList[ "Keypad_None" ] = "0xff"; 0070 //END Keypad values 0071 } 0072 0073 0074 MicrobeApp::~MicrobeApp() 0075 { 0076 } 0077 0078 0079 QString MicrobeApp::compile( const QString & url, bool optimize ) 0080 { 0081 QFile file( url ); 0082 if( file.open( QIODevice::ReadOnly ) ) 0083 { 0084 QTextStream stream(&file); 0085 unsigned line = 0; 0086 while( !stream.atEnd() ) 0087 m_program += SourceLineMicrobe( stream.readLine(), url, line++ ); 0088 file.close(); 0089 simplifyProgram(); 0090 } 0091 else 0092 { 0093 m_errorReport += i18n("Could not open file '%1'\n", url); 0094 return nullptr; 0095 } 0096 0097 Parser parser(this); 0098 0099 // Extract the PIC ID 0100 if ( !m_program.isEmpty() ) 0101 { 0102 m_picType = PIC14::toType( m_program[0].text() ); 0103 m_program.erase( m_program.begin() ); 0104 } 0105 0106 PIC14 * pic = makePic(); 0107 if ( !pic ) 0108 return nullptr; 0109 0110 Code * code = parser.parse( m_program ); 0111 pic->setCode( code ); 0112 pic->addCommonFunctions( static_cast<PIC14::DelaySubroutine>(m_maxDelaySubroutine) ); 0113 0114 pic->postCompileConstruct( m_usedInterrupts ); 0115 code->postCompileConstruct(); 0116 0117 if ( optimize ) 0118 { 0119 Optimizer opt; 0120 opt.optimize( code ); 0121 } 0122 0123 return code->generateCode( pic ); 0124 } 0125 0126 0127 PIC14 * MicrobeApp::makePic() 0128 { 0129 return new PIC14( this, static_cast<PIC14::Type>(m_picType) ); 0130 } 0131 0132 0133 void MicrobeApp::simplifyProgram() 0134 { 0135 SourceLineList simplified; 0136 0137 enum CommentType { None, SingleLine, MultiLine }; 0138 CommentType commentType = None; 0139 0140 SourceLineList::const_iterator end = m_program.end(); 0141 for ( SourceLineList::const_iterator it = m_program.begin(); it != end; ++it ) 0142 { 0143 QString code = (*it).text(); 0144 QString simplifiedLine; 0145 0146 if ( commentType == SingleLine ) 0147 commentType = None; 0148 0149 unsigned l = code.length(); 0150 0151 for ( unsigned i = 0; i < l; ++i ) 0152 { 0153 QChar c = code[i]; 0154 const char cc = c.toLatin1(); 0155 switch ( cc ) 0156 { 0157 case '/': 0158 // Look for start of comments in form "//" and "/*" 0159 0160 if ( commentType == None && (i+1 < l) ) 0161 { 0162 if ( code[i+1] == '/' ) 0163 { 0164 commentType = SingleLine; 0165 i++; 0166 } 0167 0168 else if ( code[i+1] == '*' ) 0169 { 0170 commentType = MultiLine; 0171 i++; 0172 } 0173 } 0174 break; 0175 0176 case '*': 0177 // Look for end of comments in form "*/" 0178 if ( commentType == MultiLine && (i+1 < l) && code[i+1] == '/' ) 0179 { 0180 i++; 0181 commentType = None; 0182 continue; 0183 } 0184 break; 0185 0186 case '{': 0187 case '}': 0188 // Put braces on separate lines 0189 0190 if ( commentType != None ) 0191 break; 0192 0193 simplified << SourceLineMicrobe( simplifiedLine.simplified(), (*it).url(), (*it).line() ); 0194 simplified << SourceLineMicrobe( c, (*it).url(), (*it).line() ); 0195 0196 simplifiedLine = ""; 0197 continue; 0198 } 0199 0200 if ( commentType == None ) 0201 simplifiedLine += c; 0202 } 0203 0204 simplified << SourceLineMicrobe( simplifiedLine.simplified(), (*it).url(), (*it).line() ); 0205 } 0206 0207 m_program.clear(); 0208 end = simplified.end(); 0209 for ( SourceLineList::const_iterator it = simplified.begin(); it != end; ++it ) 0210 { 0211 if ( !(*it).text().isEmpty() ) 0212 m_program << *it; 0213 } 0214 } 0215 0216 0217 void MicrobeApp::compileError( MistakeType type, const QString & context, const SourceLineMicrobe & sourceLine ) 0218 { 0219 QString message; 0220 switch (type) 0221 { 0222 case UnknownStatement: 0223 message = i18n("Unknown statement"); 0224 break; 0225 case InvalidPort: 0226 message = i18n("Port '%1' is not supported by target PIC", context); 0227 break; 0228 case UnassignedPin: 0229 message = i18n("Pin identifier was not followed by '='"); 0230 break; 0231 case NonHighLowPinState: 0232 message = i18n("Pin state can only be 'high' or 'low'"); 0233 break; 0234 case UnassignedPort: 0235 message = i18n("Invalid token '%1'. Port identifier should be followed by '='", context); 0236 break; 0237 case UnexpectedStatementBeforeBracket: 0238 message = i18n("Unexpected statement before '{'"); 0239 break; 0240 case MismatchedBrackets: 0241 message = i18n("Mismatched brackets in expression '%1'", context); 0242 break; 0243 case InvalidEquals: 0244 message = i18n("Invalid '=' found in expression"); 0245 break; 0246 case ReservedKeyword: 0247 message = i18n("Reserved keyword '%1' cannot be a variable name.", context); 0248 break; 0249 case ConsecutiveOperators: 0250 message = i18n("Nothing between operators"); 0251 break; 0252 case MissingOperator: 0253 message = i18n("Missing operator or space in operand"); 0254 break; 0255 case UnknownVariable: 0256 if ( context.isEmpty() ) 0257 message = i18n("Unknown variable"); 0258 else 0259 message = i18n("Unknown variable '%1'", context); 0260 break; 0261 case UnopenableInclude: 0262 message = i18n("Could not open include file '%1'", context); 0263 break; 0264 case DivisionByZero: 0265 message = i18n("Division by zero"); 0266 break; 0267 case NumberTooBig: 0268 message = i18n("Number too big"); 0269 break; 0270 case NonConstantStep: 0271 message = i18n("Step can only be a constant expression"); 0272 break; 0273 case NonConstantDelay: 0274 message = i18n("Delay must be a positive constant value"); 0275 break; 0276 case HighLowExpected: 0277 message = i18n("'high' or 'low' expected after pin expression '%1'", context); 0278 break; 0279 case InvalidComparison: 0280 message = i18n("Comparison operator in '%1' is not recognized"); 0281 break; 0282 case SubBeforeEnd: 0283 message = i18n("Subroutine definition before end of program"); 0284 break; 0285 case InterruptBeforeEnd: 0286 message = i18n("Interrupt routine definition before end of program"); 0287 break; 0288 case LabelExpected: 0289 message = i18n("Label expected"); 0290 break; 0291 case TooManyTokens: 0292 message = i18n("Extra tokens at end of line"); 0293 break; 0294 case FixedStringExpected: 0295 message = i18n("Expected '%1'", context); 0296 break; 0297 case PinListExpected: 0298 message = i18n("Pin list expected"); 0299 break; 0300 case AliasRedefined: 0301 message = i18n("Alias already defined"); 0302 break; 0303 case InvalidInterrupt: 0304 message = i18n("Interrupt type not supported by target PIC"); 0305 break; 0306 case InterruptRedefined: 0307 message = i18n("Interrupt already defined"); 0308 break; 0309 case ReadOnlyVariable: 0310 message = i18n("Variable '%1' is read only", context); 0311 break; 0312 case WriteOnlyVariable: 0313 message = i18n("Variable '%1' is write only", context); 0314 break; 0315 case InvalidPinMapSize: 0316 message = i18n("Invalid pin list size"); 0317 break; 0318 case VariableRedefined: 0319 message = i18n("Variable '%1' is already defined", context); 0320 break; 0321 case InvalidVariableName: 0322 message = i18n("'%1' is not a valid variable name", context); 0323 break; 0324 case VariableExpected: 0325 message = i18n("Variable expected"); 0326 break; 0327 case NameExpected: 0328 message = i18n("Name expected"); 0329 break; 0330 } 0331 0332 0333 m_errorReport += QString("%1:%2:Error [%3] %4\n") 0334 .arg( sourceLine.url() ) 0335 .arg( sourceLine.line()+1 ) 0336 .arg( type ) 0337 .arg( message ); 0338 } 0339 0340 0341 bool MicrobeApp::isValidVariableName( const QString & variableName) 0342 { 0343 0344 //*****modified checking is included for preventing the uses of registername as varable name***** 0345 0346 //Prevent usage of register/port name as varable 0347 if (/*PORT-NAME*/ variableName == "PORTA" 0348 || variableName == "PORTB" 0349 || variableName == "PORTC" 0350 || variableName == "PORTD" 0351 || variableName == "PORTE" /*TRIS-NAME*/ 0352 || variableName == "TRISA" 0353 || variableName == "TRISB" 0354 || variableName == "TRISC" 0355 || variableName == "TRISD" 0356 || variableName == "TRISE" /**REGISTER-NAME**/ 0357 || variableName == "TMR0" 0358 || variableName == "PCL" 0359 || variableName == "STATUS" 0360 || variableName == "FSR" 0361 || variableName == "PCLATH" 0362 || variableName == "INTCON" 0363 || variableName == "PIR1" 0364 || variableName == "PIR2" 0365 || variableName == "TMR1L" 0366 || variableName == "TMR1H" 0367 || variableName == "T1CON" 0368 || variableName == "TMR2" 0369 || variableName == "T2CON" 0370 || variableName == "SSPBUF" 0371 || variableName == "SSPCON" 0372 || variableName == "CCPR1L" 0373 || variableName == "CCPR1H" 0374 || variableName == "CCP1CON" 0375 || variableName == "RCSTA" 0376 || variableName == "TXREG" 0377 || variableName == "RCREG" 0378 || variableName == "CCPR2L" 0379 || variableName == "CCPR2H" 0380 || variableName == "CCP2CON" 0381 || variableName == "ADRESH" 0382 || variableName == "ADCON0" /*bank0ends*/ 0383 || variableName == "OPTION_REG" 0384 || variableName == "PIE1" 0385 || variableName == "PIE2" 0386 || variableName == "PCON" 0387 || variableName == "SSPCON2" 0388 || variableName == "PR2" 0389 || variableName == "SSPADD" 0390 || variableName == "SSPSTAT" 0391 || variableName == "TXSTA" 0392 || variableName == "SPBRG" 0393 || variableName == "ADRESL" 0394 || variableName == "ADCON1" /*bank1ends*/ 0395 || variableName == "EEDATA " 0396 || variableName == "EEADR" 0397 || variableName == "EEDATH" 0398 || variableName == "EEADRH" /*bank2ends*/ 0399 || variableName == "EECON1" 0400 || variableName == "EECON2" /*bank3ends*/ ) 0401 return false; 0402 0403 //****************************modification ends******************************* 0404 0405 if ( variableName.isEmpty() ) 0406 return false; 0407 0408 if ( !variableName[0].isLetter() && variableName[0] != '_' ) 0409 return false; 0410 0411 for ( int i = 1; i < variableName.length(); ++i ) 0412 { 0413 if ( !variableName[i].isLetterOrNumber() && variableName[i] != '_' ) 0414 return false; 0415 } 0416 0417 return true; 0418 } 0419 0420 0421 void MicrobeApp::addVariable( const Variable & variable ) 0422 { 0423 if ( variable.type() == Variable::invalidType ) 0424 return; 0425 0426 if ( !isVariableKnown( variable.name() ) ) 0427 m_variables << variable; 0428 } 0429 0430 0431 Variable MicrobeApp::variable( const QString & name ) const 0432 { 0433 VariableList::const_iterator end = m_variables.end(); 0434 for ( VariableList::const_iterator it = m_variables.begin(); it != end; ++it ) 0435 { 0436 if ( (*it).name() == name ) 0437 return *it; 0438 } 0439 return Variable(); 0440 } 0441 0442 0443 bool MicrobeApp::isVariableKnown( const QString & name ) const 0444 { 0445 return variable(name).type() != Variable::invalidType; 0446 } 0447 0448 0449 void MicrobeApp::addDelayRoutineWanted( unsigned routine ) 0450 { 0451 if ( m_maxDelaySubroutine < routine ) 0452 m_maxDelaySubroutine = routine; 0453 } 0454 0455 0456 void MicrobeApp::addAlias( const QString & name, const QString & dest ) 0457 { 0458 m_aliasList[name] = dest; 0459 } 0460 0461 0462 QString MicrobeApp::alias( const QString & alias ) const 0463 { 0464 // If the string is an alias, return the real string, 0465 // otherwise just return the alias as that is the real string. 0466 AliasMap::const_iterator it = m_aliasList.find(alias); 0467 if ( it != m_aliasList.constEnd() ) 0468 return it.value(); 0469 return alias; 0470 } 0471 0472 0473 void MicrobeApp::setInterruptUsed(const QString &interruptName) 0474 { 0475 // Don't add it again if it is already in the list 0476 if ( m_usedInterrupts.contains( interruptName ) ) 0477 return; 0478 m_usedInterrupts.append(interruptName); 0479 } 0480 0481 0482 bool MicrobeApp::isInterruptUsed( const QString & interruptName ) 0483 { 0484 return m_usedInterrupts.contains( interruptName ); 0485 } 0486 0487 0488 QString MicrobeApp::dest() const 0489 { 0490 return QString("__op%1").arg(m_dest); 0491 } 0492 0493 0494 void MicrobeApp::incDest() 0495 { 0496 m_dest++; 0497 // if ( ++m_dest > m_highestDest ) 0498 // m_highestDest = m_dest; 0499 } 0500 0501 0502 void MicrobeApp::decDest() 0503 { 0504 m_dest--; 0505 } 0506 0507 0508 void MicrobeApp::resetDest() 0509 { 0510 m_dest = 0; 0511 } 0512 //END class MicrobeApp 0513 0514 0515 0516 //BEGIN class SourceLineMicrobe 0517 SourceLineMicrobe::SourceLineMicrobe( const QString & text, const QString & url, int line ) 0518 { 0519 m_text = text; 0520 m_url = url; 0521 m_line = line; 0522 } 0523 0524 0525 SourceLineMicrobe::SourceLineMicrobe() 0526 { 0527 m_line = -1; 0528 } 0529 0530 0531 QStringList SourceLineMicrobe::toStringList( const SourceLineList & lines ) 0532 { 0533 QStringList joined; 0534 SourceLineList::const_iterator end = lines.end(); 0535 for ( SourceLineList::const_iterator it = lines.begin(); it != end; ++it ) 0536 joined << (*it).text(); 0537 return joined; 0538 0539 } 0540 //END class SourceLineMicrobe 0541