LCOV - code coverage report
Current view: top level - src/compiler - parser.cpp (source / functions) Hit Total Coverage
Test: flower-f.info Lines: 1065 1192 89.3 %
Date: 2022-06-10 00:44:15 Functions: 52 52 100.0 %

          Line data    Source code
       1             : #include <iostream>
       2             : #include <cstring>
       3             : #include <utility>
       4             : #include <vector>
       5             : #include <cassert>
       6             : #include "common/exprtype.hpp"
       7             : #include "common/tables.hpp"
       8             : #include "common/obstacle.hpp"
       9             : #include "compiler/parser.hpp"
      10             : #define C_IS_ALPHA ((c >= 'a') && (c <= 'z') || (c >= 'A') && (c <= 'Z') || (c == '_'))
      11             : #define C_IS_NUM ((c >= '0') && (c <= '9'))
      12             : 
      13             : // Быстрый алгоритм возведения x в степень n
      14          19 : int Parser::fastPow(int x, int n) {
      15          19 :     int r = 1;
      16          41 :     while (n != 0) {
      17          22 :         if ( (n & 1) == 1) r *= x;
      18          22 :         x *= x;
      19          22 :         n >>= 1;
      20             :     }
      21          19 :     return r;
      22             : }
      23             : 
      24          54 : void Parser::load(std::string name) {
      25          54 :     code.open(name);
      26          54 :     if (!code.is_open()) {
      27           0 :         std::cout << "Файл " << name << " не найден!\n";
      28           0 :         exit(-1);
      29             :     }
      30          54 : }
      31             : 
      32          51 : Parser::~Parser(void) {
      33          51 :     code.close();
      34          51 : }
      35             : 
      36          51 : bool Parser::parse(void) {
      37          51 :     code >> c;
      38             : 
      39          51 :     IdTable.pushType(_LABEL_);
      40          51 :     IdentTable * progOffset = IdTable.confirm();
      41          51 :     poliz.pushVal(progOffset);
      42          51 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
      43             :     try {
      44             : 
      45           3 :         do {
      46          54 :             if (fileQueue.size() != 0) {
      47           3 :                 code.swap(*fileQueue.back());
      48           3 :                 fileQueue.back()->close();
      49           3 :                 delete fileQueue.back();
      50           3 :                 fileQueue.pop_back();
      51           3 :                 code >> c;
      52             :             }
      53             : 
      54         137 :             while (!code.eof()) {
      55          91 :                 if (readWord("program")) {
      56          45 :                     progOffset->setVal(new int (poliz.getSize()));
      57          45 :                     program();
      58          46 :                 } else if (readWord("struct"))
      59          16 :                     defStruct();
      60          30 :                 else if (readWord("def"))
      61          26 :                     defFunction();
      62           4 :                 else if (readWord("include"))
      63           3 :                     include();
      64           1 :                 else throw Obstacle(WRONG_SCOPE);
      65          83 :                 code >> c;
      66             :             }
      67          46 :         } while (fileQueue.size() != 0);
      68             :         
      69             :        
      70             :     }
      71           8 :     catch(Obstacle & o) {
      72           8 :         ok = false;
      73           8 :         c.where();
      74           8 :         o.describe();
      75           8 :         c.cite(code);
      76           8 :         c.line++;
      77             :     }
      78          51 :     return ok;
      79             : }
      80             : 
      81           3 : void Parser::include() {
      82           6 :     std::string incfile;
      83             :     
      84           3 :     if ((c == ' ') || (c == '\n')) code >> c;
      85           3 :     if (c == '\"') {
      86          51 :         do {
      87          53 :             code >>= c;
      88          53 :             incfile.push_back(c.symbol());
      89          53 :         } while ((c != '\"') && (!code.eof()));
      90           2 :         incfile.pop_back();
      91           2 :         code >> c;
      92             :     } else {
      93          26 :         do {
      94          27 :             incfile.push_back(c.symbol());
      95          27 :             code >>= c;
      96          27 :         } while ((c != ';') && (!code.eof()));
      97             :     }
      98             : 
      99             :     #ifdef DEBUG
     100             :     std::cout << "Переключаюсь на файл \"" << incfile << "\"\n";
     101             :     #endif
     102             : 
     103           3 :     std::ifstream * mainFile = new std::ifstream;
     104           3 :     mainFile->swap(code);
     105           3 :     fileQueue.push_back(mainFile);
     106           3 :     load(incfile);
     107           3 :     if ((c == ' ') || (c == '\n')) code >> c;
     108           3 : }
     109             : 
     110          26 : void Parser::defFunction(void) {
     111          26 :     inFunc = true;
     112          26 :     IdentTable * thisFunc = IdTable.confirm();
     113          26 :     thisFunc->setFunc();
     114          26 :     thisFunc->setOffset( poliz.getSize() );
     115          26 :     if ((c == ' ') || (c == '\n')) code >> c;
     116          26 :     char * name = identificator();
     117          26 :     thisFunc->setId(name);
     118          26 :     if (c != '(') throw Obstacle(FUNC_OPENBR);
     119          25 :     code >> c;
     120             : 
     121          25 :     IdentTable * formalParams = nullptr;
     122          25 :     if (c != ')') {
     123          20 :         IdTable.last()->setOrd(0);
     124          20 :         type();
     125          20 :         formalParams = def();
     126             : 
     127          21 :         while (c == ';') {
     128           1 :             code >> c;
     129           1 :             type();
     130           1 :             def();
     131             :         }
     132             : 
     133          20 :         if (c != ')') throw Obstacle(FUNC_CLOSEBR);
     134             :     }
     135             :     
     136             :     int paramsNum;
     137          24 :     if (formalParams != nullptr)
     138          19 :         paramsNum = IdTable.last()->getOrd() - formalParams->getOrd();
     139           5 :     else paramsNum = 0;
     140             : 
     141          24 :     thisFunc->setParams(paramsNum);
     142             : 
     143          24 :     if (paramsNum != 0)
     144          19 :         thisFunc->setVal(formalParams);
     145             :     
     146          24 :     IdentTable * p = formalParams;
     147          24 :     int paramsSum = 0;
     148          48 :     for (int i = 0; i < paramsNum; i++) {
     149          24 :         if (p->isShared()) {
     150           4 :             int nparamFact = 0;
     151           4 :             if (p->getType() == _STRUCT_) {
     152           1 :                 IdentTable * fields = reinterpret_cast<IdentTable*>(p->getVal());
     153           4 :                 while (fields->next != nullptr) {
     154           3 :                     nparamFact++;
     155           3 :                     fields = fields->next;
     156             :                 }
     157           3 :             } else nparamFact = 1;
     158             :             
     159          10 :             for (int k = 0; k < nparamFact; k++) {
     160           6 :                 IdTable.pushVal(new int (k + paramsSum));
     161           6 :                 IdTable.pushType(_INT_);
     162           6 :                 poliz.pushVal(IdTable.confirm());
     163           6 :                 poliz.pushOp(_NONE_, _INT_, SHARE);
     164             :             }
     165             : 
     166           4 :             paramsSum += nparamFact;
     167             :         }
     168          24 :         if (p->getType() == _STRUCT_) {
     169           3 :             IdentTable * fields = reinterpret_cast<IdentTable*>(p->getVal());
     170          11 :             while (fields->next != nullptr) {
     171           8 :                 fields->setReg(true);
     172           8 :                 fields = fields->next;
     173             :             }
     174          21 :         } else p->setReg(true);
     175          24 :         p = p->next;
     176             :     }
     177             : 
     178          24 :     code >> c;
     179             :     
     180          24 :     if (c == ':') {
     181          23 :         code >> c;
     182             : 
     183          23 :         if (readWord("shared")) {
     184           1 :             thisFunc->setShared();
     185           1 :             code >> c;
     186             :         }
     187             : 
     188          23 :         if (readWord("int"))
     189          11 :             thisFunc->setType(_INT_);
     190          12 :         else if (readWord("string"))
     191           3 :             thisFunc->setType(_STRING_);
     192           9 :         else if (readWord("real"))
     193           6 :             thisFunc->setType(_REAL_);
     194           3 :         else if (readWord("bool"))
     195           1 :             thisFunc->setType(_BOOLEAN_);
     196           2 :         else if (readWord("struct")) {
     197           1 :             code >> c;
     198           1 :             char * stName = identificator();
     199           1 :             thisFunc->setType(_STRUCT_);
     200           1 :             thisFunc->setStruct(stName);
     201             :             //IdTable.pushStruct(stName);
     202           1 :         } else throw Obstacle(NO_TYPE);
     203           1 :     } else throw Obstacle(PROCEDURE);
     204             : 
     205          22 :     retTypes.push_back(std::make_pair(thisFunc->getType(), thisFunc->getStruct()));
     206             : 
     207          22 :     if ((c == ' ') || (c == '\n')) code >> c;
     208          22 :     if (c != '{') throw Obstacle(PROG_OPENBR);
     209          22 :     code >> c;
     210             : 
     211          22 :     defs();
     212          22 :     operations();
     213             : 
     214          22 :     retTypes.pop_back();
     215             :     
     216          22 :     if (c != '}') throw Obstacle(PROG_CLOSEBR); // никогда не будет исполнено
     217          22 :     if (inFunc) throw Obstacle(NO_RETURN);
     218             : 
     219         159 :     while (formalParams != nullptr) {
     220         138 :         formalParams->fade();
     221         138 :         formalParams = formalParams->next;
     222             :     }
     223          21 :     inFunc = false;
     224          21 : }
     225             : 
     226          22 : void Parser::returnOp(void) {
     227          22 :     inFunc = false;
     228          22 :     code >> c;
     229             :     
     230          22 :     int fieldSize = 1;
     231          22 :     char * stName = retTypes.back().second;
     232          22 :     if (retTypes.back().first == _STRUCT_) {
     233           1 :         fieldSize = StTable.getStruct(stName)->getFields().last()->getOrd();
     234             :     }
     235          22 :     type_t retFact = expr(&fieldSize, stName);
     236             : 
     237          20 :     if (retFact != retTypes.back().first) 
     238           1 :         throw Obstacle(RETURN_TYPE_MISMATCH);
     239          19 :     if (c != ';') throw Obstacle(SEMICOLON);
     240          19 :     code >> c;
     241          19 :     poliz.pushOp(_INT_, _LABEL_, RET);
     242          19 : }
     243             : 
     244          45 : void Parser::program(void) {
     245          45 :     if ((c == ' ') || (c == '\n')) code >> c;
     246          45 :     if (c != '{') throw Obstacle(PROG_OPENBR);
     247          45 :     code >> c;
     248             : 
     249          45 :     defs();
     250          43 :     operations();
     251             : 
     252          43 :     if (c != '}') throw Obstacle(PROG_CLOSEBR);
     253          43 :     poliz.pushOp(_NONE_, _NONE_, STOP);
     254          43 : }
     255             : 
     256          16 : void Parser::defStruct(void) {
     257          16 :     if ((c == ' ') || (c == '\n')) code >> c;
     258          16 :     char * name = identificator();
     259          16 :     StTable.pushName(name);
     260          16 :     if ((c == ' ') || (c == '\n')) code >> c;
     261          16 :     if (c != '{')
     262           0 :         throw Obstacle(BAD_STRUCT);
     263          16 :     code >> c;
     264           5 :     do {        
     265             :         type_t field_type;
     266          21 :         char * struct_name = nullptr;
     267          21 :         char * field_name = nullptr;
     268          21 :         bool shared = false;
     269             : 
     270          21 :         if (readWord("shared")) {
     271           1 :             if (c != ' ') throw Obstacle(TYPE_UNKNOWN);
     272           1 :             shared = true;
     273           1 :             code >> c;
     274             :         }
     275             : 
     276          21 :         if (readWord("int"))
     277           9 :             field_type = _INT_;
     278          12 :         else if (readWord("string"))
     279           2 :             field_type = _STRING_;
     280          10 :         else if (readWord("real"))
     281           4 :             field_type = _REAL_;
     282           6 :         else if (readWord("bool"))
     283           3 :             field_type = _BOOLEAN_;
     284           3 :         else if (readWord("struct")) {
     285           3 :             if (c != ' ') throw Obstacle(TYPE_UNKNOWN);
     286           3 :             code >> c;
     287           3 :             struct_name = identificator();
     288           3 :             field_type = _STRUCT_;
     289           0 :         } else throw Obstacle(TYPE_UNKNOWN);
     290             : 
     291          21 :         if (c != ' ') throw Obstacle(TYPE_UNKNOWN);
     292             : 
     293          16 :         do {
     294          37 :             code >> c;
     295          37 :             field_name = identificator();
     296          37 :             StTable.pushField(field_type, field_name, struct_name, shared);
     297          37 :             if ((c == ' ') || (c == '\n')) code >> c;
     298          37 :         } while (c == ',');
     299             : 
     300          21 :         if (c != ';') throw Obstacle(SEMICOLON);
     301          21 :         code >> c;
     302          21 :     } while (c != '}');
     303          16 :     StTable.confirm();
     304          16 : }
     305             : 
     306         135 : void Parser::defs(void) {
     307         135 :     while (type()) {
     308          68 :         def();
     309          68 :         if (c != ';') throw Obstacle(SEMICOLON);
     310          68 :         code >> c;
     311             :     }
     312          65 : }
     313             : 
     314          89 : IdentTable * Parser::def(void) {
     315          89 :     IdentTable * r = nullptr;
     316             :     try {
     317          33 :         do {
     318         122 :             code >> c;
     319         122 :             if (r == nullptr) {
     320          89 :                 r = variable();
     321          84 :                 r->setMainTable(&IdTable);
     322          33 :             } else variable()->setMainTable(&IdTable);
     323         117 :             if ((c == ' ') || (c == '\n')) code >> c;
     324         117 :         } while (c == ',');
     325          10 :     } catch(Obstacle & o) {
     326           5 :         IdTable.last()->setId(nullptr);
     327           5 :         ok = false;
     328           5 :         c.where();
     329           5 :         o.describe();
     330           5 :         c.cite(code);
     331           5 :         c.line++;
     332           5 :         revert(1); // исправление двоеточия
     333             :     }
     334          89 :     return r;
     335             : }
     336             : 
     337         168 : bool Parser::typeModificator(void) {
     338         168 :     bool r = true;
     339             : 
     340         168 :     if (readWord("shared")) {
     341           8 :         IdTable.last()->setShared();
     342           8 :         if (c != ' ') throw Obstacle(BAD_TYPE);
     343           7 :         code >> c;
     344             :     }
     345         160 :     else r = false;
     346             :     
     347         167 :     return r;
     348             : }
     349             : 
     350         168 : bool Parser::type(void) {
     351         168 :     bool r = true;
     352         168 :     bool tmod = typeModificator();
     353             : 
     354         167 :     if (readWord("int"))
     355          47 :         IdTable.pushType(_INT_);
     356         120 :     else if (readWord("string"))
     357           8 :         IdTable.pushType(_STRING_);
     358         112 :     else if (readWord("real"))
     359          15 :         IdTable.pushType(_REAL_);
     360          97 :     else if (readWord("bool"))
     361           6 :         IdTable.pushType(_BOOLEAN_);
     362          91 :     else if (readWord("struct")) {
     363          20 :         code >> c;
     364          20 :         char * stName = identificator();
     365          20 :         IdTable.pushStruct(stName);
     366          20 :         IdTable.pushType(_STRUCT_);
     367          20 :         IdentTable & templateFields = StTable.getStruct(stName)->getFields();
     368          20 :         IdTable.pushVal(new IdentTable(templateFields));
     369          71 :     } else r = false;
     370             : 
     371         167 :     if (tmod && (!r))
     372           1 :         throw Obstacle(MODIF_WITHOUT_TYPE);
     373             : 
     374         166 :     return r && (c == ' ');
     375             : }
     376             : 
     377             : /* Перед выполнением:
     378             :  * aab bba aca
     379             :  *     ^~~ <= курсор на первой букве слова
     380             :  * После выполнения:
     381             :  * aab bba aca
     382             :  *        ^ <= курсор за последней буквой слова (если true)
     383             :  * Если false, курсор на начальной позиции
     384             :  */ 
     385        5378 : bool Parser::readWord(const char * word) {
     386        5378 :     bool r = true;
     387             :     int i;
     388        7875 :     for (i = 0; word[i] != '\0'; i++) {
     389        7410 :         if (c != word[i]) { r = false; break; }
     390        2497 :         code >>= c;
     391             :     }
     392             :     // Каждое слово должно отделяться пробелом или знаком препинания
     393        5378 :     if (C_IS_NUM || C_IS_ALPHA) r = false;
     394        5378 :     if (!r) revert(i);
     395        5378 :     return r;
     396             : }
     397             : 
     398          97 : void Parser::assign(IdentTable * lval) {
     399          97 :     type_t lvtype = lval->getType();
     400             : 
     401          97 :     if ((lvtype == _STRUCT_) && (c == '{')) {
     402           6 :         IdentTable * fields = static_cast<IdentTable *>(lval->getVal());
     403          10 :         do {
     404          16 :             code >> c;
     405          16 :             char * fieldName = identificator();
     406          16 :             IdentTable * val = fields->getIT(fieldName);
     407             : 
     408          16 :             if ((c == ' ') || (c == '\n')) code >> c;
     409             : 
     410          16 :             while (c == '.') {
     411           0 :                 code >> c;
     412           0 :                 fieldName = identificator();
     413           0 :                 IdentTable * innerFields = static_cast<IdentTable *>(val->getVal());
     414           0 :                 val = innerFields->getIT(fieldName);
     415           0 :                 if ((c == ' ') || (c == '\n')) code >> c;
     416             :             }
     417             : 
     418          16 :             if (c != '=') throw Obstacle(BAD_EXPR);
     419          16 :             code >> c;
     420          16 :             assign(val);
     421          16 :         } while (c == ',');
     422           6 :         if (c != '}') throw Obstacle(BAD_EXPR);
     423           6 :         code >> c;
     424             :         
     425             :     } else {
     426          91 :         int fieldSize = unrollStruct(lval);
     427          91 :         char * strName = nullptr;
     428             : 
     429         182 :         std::vector<type_t> fieldTypes;
     430          91 :         if (lvtype == _STRUCT_) {
     431          11 :             strName = lval->getStruct();
     432          11 :             fieldTypes = StTable.getTypes(lval->getStruct());
     433             :         }
     434             : 
     435          91 :         type_t exop = expr(&fieldSize, strName);
     436          85 :         expressionType(lvtype, exop, ASSIGN);
     437             :         
     438          85 :         if (lvtype == _STRUCT_) {
     439          39 :             for (int i = 0; i < fieldSize; i++) {
     440          30 :                 type_t t = fieldTypes[i];
     441             :                 // В expr => constExpr проверяется корректность типа
     442          30 :                 poliz.pushOp(t, t, ASSIGN);
     443             :             }
     444             :         } else {
     445          76 :             poliz.pushOp(lvtype, exop, ASSIGN);
     446             :         }
     447             : 
     448          85 :         if (exop == _STRUCT_)
     449           9 :             repack(fieldSize);
     450             :         
     451             :         
     452          85 :         if ((c == ' ') || (c == '\n')) code >> c;
     453             :     }
     454          91 : }
     455             : 
     456         412 : int Parser::unrollStruct(IdentTable * lval, int ord) {
     457         412 :     int fieldSize = 0;
     458         412 :     if (lval->getType() == _STRUCT_){
     459          28 :         IdentTable * fields = static_cast<IdentTable *>(lval->getVal());
     460         107 :         while (fields->next != nullptr) {
     461          79 :             int newOrd = -1;
     462          79 :             if (fields->isReg())
     463           6 :                 newOrd = fields->getOrd();
     464          79 :             fieldSize += unrollStruct(fields, newOrd);
     465          79 :             fields = fields->next;
     466             :         }
     467             :         #ifdef DEBUG
     468             :         std::cout << "РАЗМЕР " << fieldSize << std::endl;
     469             :         #endif
     470             :     } else {
     471         384 :         fieldSize = 1;
     472         384 :         poliz.pushVal(lval);
     473             :     }
     474         412 :     return fieldSize;
     475             : }
     476             : 
     477         122 : IdentTable * Parser::variable(void) {
     478         122 :     IdTable.dupType();
     479         122 :     char * name = identificator();
     480         122 :     IdTable.pushId(name);
     481         121 :     if ((c == ' ') || (c == '\n')) code >> c;
     482         121 :     if (c == '=') constVal();
     483         117 :     return IdTable.confirm();
     484             : }
     485             : 
     486         742 : char * Parser::identificator(void) {
     487         742 :     if (!C_IS_ALPHA) throw Obstacle(BAD_IDENT);
     488         741 :     char * ident = new char[MAXIDENT];
     489         741 :     int i = 0;
     490         742 :     do {
     491        1483 :         ident[i++] = c.symbol();
     492        1483 :         code >>= c;
     493        1483 :     } while (C_IS_ALPHA);
     494         741 :     ident[i] = '\0';
     495         741 :     return ident;
     496             : }
     497             : 
     498          15 : void Parser::constStruct(IdentTable * fields) {
     499             : 
     500          15 :     if (c != '{') throw Obstacle(BAD_EXPR);
     501             : 
     502          17 :     do {
     503          32 :         code >> c;
     504          32 :         char * fieldName = identificator();
     505          32 :         IdentTable * val = fields->getIT(fieldName);
     506          32 :         type_t tval = val->getType();
     507          32 :         if ((c == ' ') || (c == '\n')) code >> c;
     508          32 :         if (c != '=') throw Obstacle(BAD_EXPR);
     509          32 :         code >> c;
     510             : 
     511          32 :         switch (tval) {
     512           8 :             case _INT_:
     513           8 :                 val->setVal( new int (constInt()) );
     514           8 :                 break;
     515           4 :             case _STRING_:
     516           4 :                 val->setVal( constString() );
     517           4 :                 break;
     518           7 :             case _REAL_:
     519           7 :                 val->setVal( new float (constReal()) );
     520           7 :                 break;
     521          10 :             case _BOOLEAN_:
     522          10 :                 val->setVal( new bool (constBool()) );
     523          10 :                 break;
     524           3 :             case _STRUCT_:
     525           3 :                 constStruct(static_cast<IdentTable *>(val->getVal()));
     526           3 :                 break;
     527           0 :             default:
     528           0 :                 throw Obstacle(PANIC);
     529             :         }
     530          32 :         if ((c == ' ') || (c == '\n')) code >> c;
     531          32 :     } while (c == ',');
     532          15 :     if (c != '}') throw Obstacle(BAD_EXPR);
     533          15 :     code >> c;
     534          15 : }
     535             : 
     536          41 : void Parser::constVal(void) {
     537          41 :     IdentTable * val = IdTable.last();
     538          41 :     type_t tval = val->getType();
     539             : 
     540          41 :     code >> c;
     541             : 
     542          41 :     switch(tval) {
     543          19 :         case _INT_:
     544          19 :             IdTable.pushVal( new int (constInt()) );
     545          18 :             break;
     546           4 :         case _STRING_:
     547           4 :             IdTable.pushVal( constString() );
     548           3 :             break;
     549           4 :         case _REAL_:
     550           4 :             IdTable.pushVal( new float (constReal()) );
     551           3 :             break;
     552           2 :         case _BOOLEAN_:
     553           2 :             IdTable.pushVal( new bool (constBool()) );
     554           1 :             break;
     555          12 :         case _STRUCT_:
     556          12 :             constStruct(static_cast<IdentTable *>(val->getVal()));
     557          12 :             break;
     558           0 :         default:
     559           0 :             throw Obstacle(PANIC);
     560             :     }
     561          37 : }
     562             : 
     563         498 : int Parser::constInt(void) {
     564         498 :     int x = 0, sign = 1;
     565         498 :     if (c == '-') {
     566           3 :         sign = -1;
     567           3 :         code >> c;
     568         495 :     } else if (c == '+') code >> c;
     569             : 
     570         498 :     if (!C_IS_NUM) throw Obstacle(BAD_INT);
     571             : 
     572          35 :     do {
     573         256 :         x = 10 * x + ( c.symbol() - '0');
     574         256 :         code >>= c;
     575         256 :     } while (C_IS_NUM);
     576         221 :     x = x * sign;
     577             : 
     578         221 :     return x;
     579             : }
     580             : 
     581          99 : char * Parser::constString(void) {
     582          99 :     if (c != '\"') throw Obstacle(BAD_STRING);
     583             : 
     584          98 :     int start = code.tellg();
     585        1503 :     do { code >>= c; }
     586        1503 :     while ((!code.eof()) && (c != '\"'));
     587             : 
     588          98 :     if (code.eof()) throw Obstacle(BAD_STRING);
     589             : 
     590          98 :     int len = (int)code.tellg() - start - 1;
     591          98 :     code.seekg(start);
     592             : 
     593          98 :     char *x = new char[len + 1];
     594             : 
     595        1503 :     for (int i = 0; i < len; i++) {
     596        1405 :         code >>= c;
     597        1405 :         x[i] = c.symbol();
     598             :     }
     599             : 
     600          98 :     x[len] = '\0';
     601             : 
     602          98 :     code >>= c; // кавычка
     603          98 :     code >>= c;
     604             : 
     605          98 :     return x;
     606             : }
     607             : 
     608         379 : float Parser::constReal(void) {
     609         379 :     int intPart = constInt();
     610             : 
     611         103 :     if (c != '.') throw Obstacle(BAD_REAL);
     612          16 :     code >>= c;
     613             : 
     614          16 :     if (!C_IS_NUM) throw Obstacle(BAD_REAL);
     615             : 
     616          16 :     int x = 1;
     617          16 :     float floatPart = 0;
     618           3 :     do {
     619          19 :         floatPart += (float)( c.symbol() - '0') / fastPow(10, x++);
     620          19 :         code >>= c;
     621          19 :     } while (C_IS_NUM);
     622             : 
     623          16 :     if (intPart < 0) floatPart *= -1;
     624             : 
     625          16 :     return intPart + floatPart;
     626             : }
     627             : 
     628          12 : bool Parser::constBool(void) {
     629             :     bool r;
     630          12 :     if (readWord("true")) r = true;
     631           6 :     else if (readWord("false")) r = false;
     632           1 :     else throw Obstacle(BAD_BOOL);
     633             : 
     634          11 :     return r;
     635             : }
     636             : 
     637         285 : void Parser::operations(void) {
     638         285 :     while (c != '}') {
     639         205 :         try { operation(); }
     640          42 :         catch(Obstacle & o) {
     641          21 :             ok = false;
     642          21 :             c.where();
     643          21 :             o.describe();
     644          21 :             c.cite(code);
     645          21 :             c.line++;
     646          21 :             code >> c;
     647             :         }
     648             :     }
     649          80 : }
     650             : 
     651         251 : void Parser::operation(void) {
     652             : 
     653         251 :     if (c.symbol() == '}') return;
     654         251 :     else if (readWord("if")) condOp();
     655         236 :     else if (readWord("for")) forOp();
     656         224 :     else if (readWord("while")) whileOp();
     657         218 :     else if (readWord("break")) breakOp();
     658         215 :     else if (readWord("continue")) continueOp();
     659         213 :     else if (readWord("write")) writeOp();
     660         132 :     else if (readWord("goto")) gotoOp();
     661         127 :     else if (readWord("read")) readOp();
     662         109 :     else if (readWord("bytecode")) bytecodeOp();
     663         105 :     else if (readWord("return")) returnOp();
     664          83 :     else if (readWord("thread")) threadOp();
     665          77 :     else if (readWord("fork")) forkOp();
     666          76 :     else if (readWord("lock")) lockOp();
     667          75 :     else if (readWord("{")) {
     668          11 :         code >> c;
     669          11 :         operations();
     670          11 :         if (c != '}')
     671           0 :             throw Obstacle(OP_CLOSEBR);
     672          11 :         code >> c;
     673             :     } else {
     674          64 :         char * name = identificator();
     675          64 :         if ((c == ' ') || (c == '\n')) code >> c;
     676             : 
     677          64 :         if (c == ':') {
     678           6 :             code >> c;
     679           6 :             saveLabel(name, poliz.getSize());
     680           6 :             operation();
     681             :         } else {
     682          58 :             IdentTable * lval = IdTable.getIT(name);
     683          66 :             while (c == '.') {
     684           8 :                 code >> c;
     685           8 :                 name = identificator();
     686           8 :                 IdentTable * fields = static_cast<IdentTable *>(lval->getVal());
     687           8 :                 lval = fields->getIT(name);
     688           8 :                 if ((c == ' ') || (c == '\n')) code >> c;
     689             :             }
     690          58 :             if (c != '=') throw Obstacle(BAD_OPERATOR);
     691          58 :             code >> c;
     692          58 :             assign(lval);
     693          52 :             if (c != ';') throw Obstacle(SEMICOLON);
     694          52 :             code >> c;
     695             :         }
     696             :     }
     697             : 
     698             : }
     699             : 
     700           6 : void Parser::threadOp(void) {
     701           6 :     if (inThread)
     702           1 :         throw Obstacle(NESTED_THREADS);
     703             : 
     704           5 :     if ((c == ' ') || (c == '\n')) code >> c;
     705             : 
     706           5 :     if (c != ':')
     707           1 :         throw Obstacle(NEED_THREAD_NUMBER);
     708             : 
     709           4 :     code >> c;
     710           4 :     inThread = true;
     711             : 
     712           4 :     IdTable.pushType(_LABEL_);
     713           4 :     IdentTable * progOffset = IdTable.confirm();
     714           4 :     poliz.pushVal(progOffset);
     715           4 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
     716             : 
     717           4 :     int threadNum = constInt();
     718           4 :     IdTable.pushType(_LABEL_);
     719           4 :     IdTable.pushVal( new int (poliz.getSize()) );
     720           4 :     IdTable.pushId(nullptr);
     721           4 :     threads[threadNum] = IdTable.confirm();
     722             :     
     723           4 :     if ((c == ' ') || (c == '\n')) code >> c;
     724             : 
     725           4 :     if (c != '{')
     726           0 :         throw Obstacle(PROG_OPENBR);
     727           4 :     code >> c;
     728             : 
     729           4 :     operations();
     730             :     
     731           4 :     poliz.pushOp(_NONE_, _NONE_, STOP);
     732             : 
     733           4 :     if (c != '}')
     734           0 :         throw Obstacle(PROG_CLOSEBR);
     735             :     
     736           4 :     progOffset->setVal(new int (poliz.getSize()));
     737             : 
     738           4 :     code >> c;
     739           4 :     inThread = false;
     740           4 : }
     741             : 
     742           1 : void Parser::forkOp(void) {
     743           1 :     if ((c == ' ') || (c == '\n')) code >> c;
     744           1 :     if (c != '(')
     745           0 :         throw Obstacle(FUNC_OPENBR);
     746             : 
     747           1 :     do {
     748           2 :         code >> c;
     749           2 :         int threadNum = constInt();
     750           2 :         poliz.pushVal(threads[threadNum]);
     751           2 :         poliz.pushOp(_NONE_, _INT_, FORK);
     752           2 :         if ((c == ' ') || (c == '\n')) code >> c;
     753           2 :     } while (c == ',');
     754             : 
     755           1 :     if (c != ')')
     756           0 :         throw Obstacle(FUNC_CLOSEBR);
     757           1 :     code >> c;
     758           1 :     if (c != ';')
     759           0 :         throw Obstacle(SEMICOLON);
     760             : 
     761           1 :     code >> c;
     762           1 : }
     763             : 
     764           1 : void Parser::lockOp(void) {
     765           1 :     if ((c == ' ') || (c == '\n')) code >> c;
     766           1 :     if (c != '(')
     767           0 :         throw Obstacle(FUNC_OPENBR);
     768           1 :     code >> c;
     769           1 :     if ((c == ' ') || (c == '\n')) code >> c;
     770           1 :     if (c != ')')
     771           0 :         throw Obstacle(FUNC_CLOSEBR);
     772           1 :     code >> c;
     773           1 :     if (c != ';')
     774           0 :         throw Obstacle(SEMICOLON);
     775             : 
     776           1 :     poliz.pushOp(_NONE_, _NONE_, LOCK);
     777             : 
     778           1 :     code >> c;
     779           1 : }
     780             : 
     781           9 : IdentTable * Parser::saveLabel(char * label, int addr) {
     782             :     IdentTable * existinglab;
     783             :     try {
     784           9 :         existinglab = IdTable.getIT(label, false);
     785           3 :         if (existinglab->getType() != _LABEL_)
     786           0 :             throw Obstacle(LABEL_OR_IDENT);
     787           3 :         delete static_cast<int *>(existinglab->getVal());
     788           3 :         existinglab->setVal(new int (addr));
     789             :     }
     790          12 :     catch(Obstacle & o) {
     791           6 :         if (o.r == LABEL_OR_IDENT) {
     792           0 :             ok = false;
     793           0 :             c.where();
     794           0 :             o.describe();
     795           0 :             c.cite(code);
     796           0 :             c.line++;
     797           0 :             code >> c;
     798             :         } else {
     799           6 :             IdTable.pushType(_LABEL_);
     800           6 :             IdTable.pushVal( new int (addr) );
     801           6 :             IdTable.pushId(label);
     802           6 :             existinglab = IdTable.confirm();
     803             :         }
     804             :     }
     805           9 :     return existinglab;
     806             : }
     807             : 
     808         358 : type_t Parser::expr(int * fieldSize, char * structName) {
     809         358 :     type_t r = _NONE_;
     810             : 
     811         358 :     assert(fieldSize != nullptr);
     812             : 
     813         358 :     r = andExpr(fieldSize, structName);
     814             : 
     815             :     while (true) {
     816         345 :         if (readWord("or")) {
     817           2 :             code >> c;
     818           2 :             type_t rval = andExpr(fieldSize, structName);
     819             : 
     820           2 :             if ((r == _STRUCT_) || (rval == _STRUCT_)) {
     821           1 :                 handleStruct(r, rval, LOR, fieldSize, structName);
     822           1 :                 repack(*fieldSize);
     823             :             } else
     824           1 :                 poliz.pushOp(r, rval, LOR);
     825             : 
     826           2 :             r = expressionType(r, rval, LOR);
     827         343 :         } else break;
     828           2 :     }
     829             : 
     830         343 :     return r;
     831             : }
     832             : 
     833         360 : type_t Parser::andExpr(int * fieldSize, char * structName) {
     834         360 :     type_t r = _NONE_;
     835             :     
     836         360 :     r = boolExpr(fieldSize, structName);
     837             : 
     838             :     while (true) {
     839         346 :         if (readWord("and")) {
     840           1 :             code >> c;
     841           1 :             type_t rval = boolExpr(fieldSize, structName);
     842             :             
     843           1 :             if ((r == _STRUCT_) || (rval == _STRUCT_)) {
     844           1 :                 handleStruct(r, rval, LAND, fieldSize, structName);
     845           1 :                 repack(*fieldSize);
     846             :             } else
     847           0 :                 poliz.pushOp(r, rval, LAND);
     848             : 
     849           1 :             r = expressionType(r, rval, LAND);
     850         345 :         } else break;
     851           1 :     }
     852         345 :     return r;
     853             : }
     854             : 
     855         361 : type_t Parser::boolExpr(int * fieldSize, char * structName) {
     856         361 :     type_t r = _NONE_;
     857             : 
     858         361 :     r = add(fieldSize, structName);
     859             :     
     860         346 :     if ( (c == '=') || (c == '<') || (c == '>') || (c == '!')) {
     861          28 :         operation_t op = NONE;
     862          28 :         char p = c.symbol();
     863          28 :         code >>= c;
     864          28 :         if (c == '=') {
     865          18 :             switch(p) {
     866           3 :                 case '<': op = LESSEQ; break;
     867           3 :                 case '>': op = GRTREQ; break;
     868           3 :                 case '!': op = NEQ;    break;
     869           9 :                 case '=': op = EQ;     break;
     870             :             }
     871          18 :             code >>= c;
     872             :         } else {
     873          10 :             switch(p) {
     874           6 :                 case '<': op = LESS; break;
     875           4 :                 case '>': op = GRTR; break;
     876           0 :                 default: throw Obstacle(BAD_EXPR);
     877             :             }
     878             :         }
     879          28 :         if ((c == ' ') || (c == '\n')) code >> c;
     880          28 :         type_t rval = add(fieldSize, structName);
     881             :         
     882          28 :         if ((r == _STRUCT_) || (rval == _STRUCT_)) {
     883           0 :             handleStruct(r, rval, op, fieldSize, structName);
     884           0 :             repack(*fieldSize);
     885             :         } else
     886          28 :             poliz.pushOp(r, rval, op);
     887             : 
     888          28 :         r = expressionType(r, rval, op);
     889             :     }
     890             : 
     891         346 :     return r;
     892             : }
     893             : 
     894         389 : type_t Parser::add(int * fieldSize, char * structName) {
     895         389 :     bool exit = false;
     896         389 :     bool inverse = false;
     897         389 :     if (c == '+') code >> c;
     898         389 :     if (c == '-') {
     899           1 :         inverse = true;
     900           1 :         code >> c;
     901             :     }
     902         389 :     type_t r = mul(fieldSize, structName);
     903             :     operation_t op;
     904             : 
     905             :     while (true) {
     906             : 
     907         412 :         switch (c.symbol()) {
     908          31 :             case '+': op = PLUS; break;
     909           7 :             case '-': op = MINUS; break;
     910         374 :             default: exit = true;
     911             :         }
     912         412 :         if (exit) break;
     913          38 :         code >> c;
     914          38 :         type_t rval = mul(fieldSize, structName);
     915             :         
     916          38 :         if ((r == _STRUCT_) || (rval == _STRUCT_)) {
     917           2 :             handleStruct(r, rval, op, fieldSize, structName);
     918           2 :             repack(*fieldSize);
     919             :         } else
     920          36 :             poliz.pushOp(r, rval, op);
     921             : 
     922          38 :         r = expressionType(r, rval, op);
     923          38 :     }
     924             : 
     925         374 :     if (inverse) {
     926           1 :         if (r == _STRUCT_) {
     927           0 :             handleStruct(_NONE_, r, INV, fieldSize, structName);
     928           0 :             repack(*fieldSize);
     929           0 :             r = expressionType(_NONE_, r, INV);
     930             :         }
     931             :     }
     932             : 
     933         374 :     return r;
     934             : }
     935             : 
     936           5 : void Parser::handleStruct(
     937             :     type_t lval, type_t rval, operation_t op, int * fieldSize, char * structName) {
     938             :    
     939             :    /* Если в rval лежит простой тип, то его можно просто скопировать
     940             :     * для всех остальных полей в lval. В случае, если rval -- структура,
     941             :     * то нужно аккуратно обойти все её поля. Причём constExpr гарантирует,
     942             :     * что структуры lval и rval идентичны, поэтому мы можем взять имя
     943             :     * lval (т.е. structName) для определения структуры rval.
     944             :     */
     945           5 :     assert((lval == _STRUCT_) || (rval == _STRUCT_));
     946             : 
     947          10 :     std::vector<type_t> types = StTable.getTypes(structName);
     948           5 :     int newFieldSize = types.size();
     949             :     type_t ltype, rtype;
     950          21 :     for (int i = newFieldSize - 1; i >= 0; i--) {
     951          16 :         if (lval == _STRUCT_) ltype = types[i];
     952           3 :         else ltype = lval;
     953          16 :         if (rval == _STRUCT_) rtype = types[i];
     954           5 :         else rtype = rval;
     955             : 
     956          16 :         if ((ltype == _STRUCT_) || (rtype == _STRUCT_))
     957           0 :             handleStruct(ltype, rtype, op, &newFieldSize, structName);
     958             :         else
     959          16 :             poliz.pushOp(ltype, rtype, op);
     960             :     }
     961           5 : }
     962             : 
     963         427 : type_t Parser::mul(int * fieldSize, char * structName) {
     964         427 :     bool exit = false;
     965         427 :     type_t r = constExpr(fieldSize, structName);
     966             :     operation_t op;
     967             : 
     968             :     while (true) {
     969             : 
     970         445 :         switch (c.symbol()) {
     971          21 :             case '*': op = MUL; break;
     972          10 :             case '/': op = DIV; break;
     973           2 :             case '%': op = MOD; break;
     974         412 :             default: exit = true;
     975             :         }
     976         445 :         if (exit) break;
     977          33 :         code >> c;
     978          33 :         type_t rval = constExpr(fieldSize, structName);
     979             :         
     980          33 :         if ((r == _STRUCT_) || (rval == _STRUCT_)) {
     981           1 :             handleStruct(r, rval, op, fieldSize, structName);
     982           1 :             repack(*fieldSize);
     983             :         } else
     984          32 :             poliz.pushOp(r, rval, op);
     985             : 
     986          33 :         r = expressionType(r, rval, op);
     987             : 
     988          33 :     }
     989             : 
     990         412 :     return r;
     991             : }
     992             : 
     993          14 : void Parser::repack(int fieldSize) {
     994          14 :     op_t op = poliz.getProg()[poliz.getSize() - fieldSize - 1];
     995          14 :     if ((operation_t)(op & 0xFF) == UNPACK)
     996           1 :         return;
     997             : 
     998          13 :     int POLIZsteps[2 * fieldSize];
     999         101 :     for (int i = 0; i < fieldSize * 2; i++)
    1000          88 :         POLIZsteps[i] = 1;
    1001             : 
    1002          65 :     POLIZ buff[2], opBuff[2];
    1003             : 
    1004             :     /* Каков смысл steps? В нём хранится количество элементов ПОЛИЗА,
    1005             :      * которое нужно достать для каждого поля. Вначале идёт левая,
    1006             :      * потом правая ветка.
    1007             :      */
    1008          13 :     int temp_iter = fieldSize;
    1009             :     int i;
    1010          57 :     while (((i = poliz.getSize()) > 0) && poliz.getEB()[i - 1] && temp_iter) {
    1011          44 :         op_t oper = poliz.getProg()[i - 1];
    1012          44 :         opBuff[1].push(oper, poliz.getEB()[i - 1]);
    1013          44 :         poliz.pop();
    1014          44 :         temp_iter--;
    1015             :     }
    1016          39 :     for (int buffIter = 1; buffIter >= 0; buffIter--) {
    1017         114 :         for (int nfield = fieldSize; nfield > 0; nfield--) {
    1018          88 :             int stepIdx = buffIter + (nfield - 1) * 2;
    1019          88 :             int fields = POLIZsteps[stepIdx];
    1020          88 :             POLIZsteps[stepIdx] = 0;
    1021         217 :             while (fields) {
    1022         129 :                 i = poliz.getSize();
    1023         129 :                 bool ebit = poliz.getEB()[i - 1];
    1024         129 :                 op_t oper = poliz.getProg()[i - 1];
    1025         129 :                 if (ebit) {
    1026          25 :                     int nops = operands(static_cast<operation_t>(oper & 0xFF));
    1027          25 :                     fields += nops;
    1028             :                 }
    1029             :                 
    1030         129 :                 buff[buffIter].push(oper, ebit);
    1031         129 :                 POLIZsteps[stepIdx] += 1;
    1032             :                 
    1033         129 :                 poliz.pop();
    1034         129 :                 fields--;
    1035             :             }
    1036             :         }
    1037             :     }
    1038             : 
    1039         101 :     for (int step = 0; step < fieldSize * 2; step++) {
    1040         217 :         while (POLIZsteps[step]) {
    1041         129 :             int  bi   = buff[step % 2].getSize();
    1042         129 :             bool ebit = buff[step % 2].getEB()[bi - 1];
    1043         129 :             op_t oper   = buff[step % 2].getProg()[bi - 1];
    1044         129 :             buff[step % 2].pop();
    1045         129 :             poliz.push(oper, ebit);
    1046         129 :             POLIZsteps[step] -= 1;
    1047             :         }
    1048          88 :         int  bi   = opBuff[step % 2].getSize();
    1049          88 :         if (bi > 0) {
    1050          44 :             bool ebit = opBuff[step % 2].getEB()[bi - 1];
    1051          44 :             op_t oper   = opBuff[step % 2].getProg()[bi - 1];
    1052          44 :             opBuff[step % 2].pop();
    1053          44 :             poliz.push(oper, ebit);
    1054             :         }
    1055          14 :     }
    1056             : }
    1057             : 
    1058         476 : type_t Parser::constExpr(int * fieldSize, char * structName) {
    1059             :     type_t r;
    1060             : 
    1061         476 :     if (readWord("true")) {
    1062           2 :         r = _BOOLEAN_;
    1063           4 :         NEW_IDENT(val, _BOOLEAN_, nullptr, new bool (true), fieldSize)
    1064         474 :     } else if (readWord("false")) {
    1065           1 :         r = _BOOLEAN_;
    1066           2 :         NEW_IDENT(val, _BOOLEAN_, nullptr, new bool (false), fieldSize)
    1067         473 :     } else if (readWord("not")) {
    1068           0 :         type_t val = constExpr(fieldSize, structName);
    1069           0 :         r = expressionType(_NONE_, val, LNOT);
    1070           0 :         for (int i = 0; i < *fieldSize; i++)
    1071           0 :             poliz.pushOp(_NONE_, val, LNOT);
    1072         473 :     } else if (c == '(') {
    1073          14 :         code >> c;
    1074          14 :         r = expr(fieldSize, structName);
    1075          13 :         if (c != ')') throw Obstacle(EXPR_CLOSEBR);
    1076          13 :         code >>= c;
    1077             :     } else {
    1078             :         
    1079         459 :         if (c == '\"') {
    1080          91 :             r = _STRING_;
    1081          91 :             char * x = constString();
    1082         182 :             NEW_IDENT(val, _STRING_, nullptr, x, fieldSize)
    1083             :         } else {
    1084         368 :             int start = code.tellg();
    1085             :             try {
    1086         368 :                 r = _REAL_;
    1087         368 :                 float x = constReal();
    1088          12 :                 NEW_IDENT(val, _REAL_, nullptr, new float (x), fieldSize)
    1089         724 :             } catch (Obstacle & o) {
    1090         362 :                 code.seekg(start - 1);
    1091         362 :                 code >>= c;
    1092         362 :                 if (o.r != BAD_INT) {
    1093          86 :                     r = _INT_;
    1094          86 :                     int x = constInt();
    1095         177 :                     NEW_IDENT(val, _INT_, nullptr, new int (x), fieldSize)
    1096             :                 } else {
    1097         276 :                     IdentTable * val = getFieldInStruct();
    1098         267 :                     r = val->getType();
    1099             :                     
    1100         267 :                     if (c == '(') { // Вызов функции
    1101          22 :                         if (! val->isFunc())
    1102           0 :                             throw Obstacle(NOT_CALLABLE);
    1103          22 :                         callIdent(val);
    1104             :                     } else {
    1105         245 :                         if (val->isFunc())
    1106           1 :                             throw Obstacle(CALLABLE);
    1107             : 
    1108         244 :                         if (r == _STRUCT_) {
    1109          15 :                             if ((structName != nullptr) && (strcmp(val->getStruct(), structName) != 0))
    1110           2 :                                 throw Obstacle(EXPR_BAD_TYPE);
    1111             :                         }
    1112             :                             
    1113         242 :                         int fields = unrollStruct(val);
    1114         242 :                         if (*fieldSize != 0) {
    1115         242 :                             *fieldSize = fields;
    1116             :                         }
    1117             :                         
    1118             :                     }
    1119             :                 }
    1120             :             }
    1121             :         }
    1122             :     }
    1123             : 
    1124         460 :     if ((c == ' ') || (c == '\n')) code >> c;
    1125             : 
    1126         460 :     return r;
    1127             : }
    1128             : 
    1129         276 : IdentTable * Parser::getFieldInStruct(void) {
    1130         276 :     char * name = identificator();
    1131         275 :     IdentTable * val = IdTable.getIT(name);
    1132         268 :     if ((c == ' ') || (c == '\n')) code >> c;
    1133             : 
    1134         341 :     while (c == '.') { // Добираемся до поля структуры
    1135          73 :         code >> c;
    1136          73 :         name = identificator();
    1137          73 :         IdentTable * fields = static_cast<IdentTable *>(val->getVal());
    1138          73 :         val = fields->getIT(name);
    1139          73 :         if ((c == ' ') || (c == '\n')) code >> c;
    1140             :     }
    1141         268 :     if (!val->isShared() && inThread)
    1142           1 :         throw Obstacle(PRIVATE_VAR_IN_THREAD);
    1143             :     
    1144         267 :     return val;
    1145             : }
    1146             : 
    1147          22 : void Parser::callIdent(IdentTable * val) {
    1148          22 :     code >> c;
    1149          22 :     IdentTable * fields = static_cast<IdentTable *>(val->getVal());
    1150          22 :     int paramCount = 0;
    1151          22 :     int paramCountFact = 0;
    1152          42 :     while (c != ')') {
    1153          22 :         if (fields == nullptr)
    1154           0 :             throw Obstacle(TOO_MUCH_PARAMS);
    1155          22 :         if (c == ',') code >> c;
    1156             : 
    1157          22 :         int fieldSize = 1;
    1158          22 :         char * structName = nullptr;
    1159             : 
    1160          22 :         if (fields->getType() == _STRUCT_) {
    1161           3 :             fieldSize = fields->last()->getOrd();
    1162           3 :             structName = fields->getStruct();
    1163             :         }
    1164             : 
    1165          22 :         type_t exprType = expr(&fieldSize, structName);
    1166          21 :         if (fields->getType() != exprType)
    1167           1 :             throw Obstacle(EXPR_BAD_TYPE);
    1168          20 :         fields = fields->next;
    1169          20 :         paramCount += fieldSize;
    1170          20 :         paramCountFact++;
    1171             :     }
    1172             : 
    1173          20 :     code >> c;
    1174          20 :     if (paramCountFact != val->getParams())
    1175           1 :         throw Obstacle(BAD_PARAMS_COUNT);
    1176          19 :     int fieldSize = 1;
    1177          38 :     NEW_IDENT(params, _INT_, nullptr, new int (paramCount), &fieldSize)
    1178          38 :     NEW_IDENT(callable, _LABEL_, nullptr, new int (val->getOffset()), &fieldSize)
    1179          19 :     poliz.pushOp(_INT_, _LABEL_, CALL);
    1180             :     
    1181          19 :     if (val->getType() == _STRUCT_) {
    1182           1 :         int fnum = StTable.getStruct(val->getStruct())->getFields().last()->getOrd();
    1183           1 :         IdTable.pushType(_INT_);
    1184           1 :         IdTable.pushVal(new int (fnum));
    1185           1 :         poliz.pushVal(IdTable.confirm());
    1186           1 :         poliz.pushOp(_NONE_, _INT_, UNPACK);
    1187             :     }
    1188          19 : }
    1189             : 
    1190          15 : void Parser::condOp(void) {
    1191          15 :     if ((c == ' ') || (c == '\n')) code >> c;
    1192          15 :     if (c != '(')
    1193           0 :         throw Obstacle(BAD_PARAMS_OPBR);
    1194          15 :     code >> c;
    1195             : 
    1196          15 :     int fieldSize = 1;
    1197          15 :     type_t r = expr(&fieldSize);
    1198             : 
    1199          15 :     if (r != _BOOLEAN_)
    1200           1 :         throw Obstacle(BAD_IF);
    1201             : 
    1202          14 :     if (c != ')')
    1203           0 :         throw Obstacle(BAD_PARAMS_CLBR);
    1204             : 
    1205          14 :     code >> c;
    1206             : 
    1207          14 :     IdTable.pushType(_LABEL_);
    1208          14 :     IdentTable * elsecase = IdTable.confirm();
    1209          14 :     IdTable.pushType(_LABEL_);
    1210          14 :     IdentTable * endif = IdTable.confirm();
    1211             : 
    1212          14 :     poliz.pushOp(_NONE_, _BOOLEAN_, LNOT);
    1213          14 :     poliz.pushVal(elsecase);
    1214          14 :     poliz.pushOp(_BOOLEAN_, _LABEL_, JIT);
    1215             : 
    1216          14 :     operation();
    1217             : 
    1218          14 :     poliz.pushVal(endif);
    1219          14 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1220             : 
    1221          14 :     elsecase->setVal( new int (poliz.getSize()) );
    1222             : 
    1223          14 :     if (readWord("else")) {
    1224          10 :         code >> c;
    1225          10 :         operation();
    1226             :     }
    1227             : 
    1228          14 :     endif->setVal( new int (poliz.getSize()) );
    1229          14 : }
    1230             : 
    1231          12 : IdentTable * Parser::cycleparam(void) {
    1232             :     IdentTable * lval;
    1233             :     char * name;
    1234             : 
    1235          12 :     if (type()) {
    1236             :         // переменная не описана
    1237           7 :         code >> c;
    1238           7 :         name = identificator();
    1239           7 :         IdTable.pushId(name);
    1240           7 :         lval = IdTable.confirm();
    1241             :     } else {
    1242             :         // переменная описана
    1243           5 :         name = identificator();
    1244           5 :         lval = IdTable.getIT(name);
    1245             :     }
    1246             : 
    1247          12 :     if ((c == ' ') || (c == '\n')) code >> c;
    1248             : 
    1249          13 :     while (c == '.') {
    1250           1 :         code >> c;
    1251           1 :         name = identificator();
    1252           1 :         IdentTable * fields = static_cast<IdentTable *>(lval->getVal());
    1253           1 :         lval = fields->getIT(name);
    1254           1 :         if ((c == ' ') || (c == '\n')) code >> c;
    1255             :     }
    1256             : 
    1257          12 :     if (c != '=') throw Obstacle(BAD_EXPR);
    1258          12 :     code >> c;
    1259          12 :     assign(lval);
    1260             : 
    1261          12 :     return lval;
    1262             : }
    1263             : 
    1264          12 : void Parser::forOp(void) {
    1265          12 :     IdTable.pushType(_LABEL_);
    1266          12 :     IdentTable * exit = IdTable.confirm();
    1267          12 :     exits.push(exit);
    1268          12 :     IdTable.pushType(_LABEL_);
    1269          12 :     IdentTable * body = IdTable.confirm();
    1270             : 
    1271          12 :     if ((c == ' ') || (c == '\n')) code >> c;
    1272          12 :     if (c != '(')
    1273           0 :         throw Obstacle(BAD_PARAMS_OPBR);
    1274          12 :     code >> c;
    1275             : 
    1276          12 :     IdentTable * cp = nullptr;
    1277          12 :     cp = cycleparam(); // начальное выражение
    1278             :     /*
    1279             :     try{ cp = cycleparam(); } // начальное выражение
    1280             :     catch(Obstacle & o){
    1281             :         o.describe();
    1282             :     }
    1283             :     */
    1284             :     
    1285          12 :     if (c != ';')
    1286           0 :         throw Obstacle(SEMICOLON);
    1287             : 
    1288          12 :     IdTable.pushType(_LABEL_);
    1289          12 :     IdTable.pushVal( new int (poliz.getSize()) );
    1290          12 :     IdentTable * condexpr = IdTable.confirm();
    1291          12 :     code >> c;
    1292             : 
    1293          12 :     int fieldSize = 1;
    1294          12 :     type_t e2 = expr(&fieldSize); // условие продолжения
    1295             : 
    1296          12 :     if (e2 != _BOOLEAN_) throw Obstacle(BAD_IF);
    1297          11 :     poliz.pushVal(body);
    1298          11 :     poliz.pushOp(_BOOLEAN_, _LABEL_, JIT);
    1299             :     // Здесь машина будет в случае невыполнения условия
    1300          11 :     poliz.pushVal(exit);
    1301          11 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1302             : 
    1303          11 :     if (c != ';')
    1304           0 :         throw Obstacle(SEMICOLON);
    1305             : 
    1306          11 :     IdTable.pushType(_LABEL_);
    1307          11 :     IdTable.pushVal( new int (poliz.getSize()) );
    1308          11 :     IdentTable * cyclexpr = IdTable.confirm();
    1309          11 :     steps.push(cyclexpr);
    1310             : 
    1311          11 :     code >> c;
    1312             : 
    1313          11 :     char * name = identificator();
    1314          11 :     IdentTable * cycleLval = IdTable.getIT(name);
    1315          11 :     if ((c == ' ') || (c == '\n')) code >> c;
    1316          11 :     if (c != '=') throw Obstacle(BAD_EXPR);
    1317          11 :     code >> c;
    1318          11 :     assign(cycleLval);
    1319             : 
    1320          11 :     if (c != ')')
    1321           0 :         throw Obstacle(BAD_PARAMS_CLBR);
    1322             : 
    1323          11 :     poliz.pushVal(condexpr);
    1324          11 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1325             : 
    1326          11 :     code >> c;
    1327          11 :     body->setVal(new int (poliz.getSize()) );
    1328          11 :     operation();  // тело цикла
    1329             : 
    1330             :     // Проверяем условие, если правда, то проходим через цикл. выражение
    1331             :     // и возвращаемся в тело. Иначе выходим из него.
    1332          11 :     poliz.pushVal(cyclexpr);
    1333          11 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1334             : 
    1335          11 :     exit->setVal(new int (poliz.getSize()) );
    1336             : 
    1337          11 :     exits.pop();
    1338          11 :     steps.pop();
    1339             : 
    1340          11 :     if ((cp->next->getId() == nullptr)) {
    1341           7 :         cp->setId(nullptr); // Эта переменная вне цикла не определена.
    1342             :     }
    1343          11 : }
    1344             : 
    1345           4 : void Parser::bytecodeOp(void) {
    1346           4 :     if ((c == ' ') || (c == '\n')) code >> c;
    1347           4 :     if (c != '{')
    1348           0 :         throw Obstacle(PROG_OPENBR);
    1349             : 
    1350           8 :     std::vector<type_t> types;
    1351             : 
    1352          23 :     do {
    1353          27 :         bool couldRead = true;
    1354          27 :         code >> c;
    1355          27 :         switch (c.symbol()) {
    1356           3 :             case 'A':
    1357           3 :                 if (readWord("ASSIGN")) {
    1358           3 :                     BYTECODE_OP_BIN(ASSIGN)
    1359           0 :                 } else couldRead = false;
    1360           3 :                 break;
    1361           1 :             case 'C':
    1362           1 :                 if (readWord("CALL")) {
    1363           1 :                     BYTECODE_OP_BIN(CALL)
    1364           0 :                 } else couldRead = false;
    1365           1 :                 break;
    1366           0 :             case 'D':
    1367           0 :                 if (readWord("DIV")) {
    1368           0 :                     BYTECODE_OP_BIN(DIV)
    1369           0 :                 } else couldRead = false;
    1370           0 :                 break;
    1371           2 :             case 'E':
    1372           2 :                 if (readWord("ENDL")) {
    1373           0 :                     BYTECODE_OP_BIN(ENDL)
    1374           2 :                 } else if (readWord("EQ")) {
    1375           1 :                     BYTECODE_OP_BIN(EQ)
    1376           1 :                 } else couldRead = false;
    1377           2 :                 break;
    1378           0 :             case 'G':
    1379           0 :                 if (readWord("GRTR")) {
    1380           0 :                     BYTECODE_OP_BIN(GRTR)
    1381           0 :                 } else if (readWord("GRTREQ")) {
    1382           0 :                     BYTECODE_OP_BIN(GRTREQ)
    1383           0 :                 } else couldRead = false;
    1384           0 :                 break;
    1385           0 :             case 'I':
    1386           0 :                 if (readWord("INV")) {
    1387           0 :                     BYTECODE_OP_BIN(INV)
    1388           0 :                 } else couldRead = false;
    1389           0 :                 break;
    1390           2 :             case 'J':
    1391           2 :                 if (readWord("JIT")) {
    1392           1 :                     BYTECODE_OP_BIN(JIT)
    1393           1 :                 } else if (readWord("JMP")) {
    1394           1 :                     BYTECODE_OP_BIN(JMP)
    1395           0 :                 } else couldRead = false;
    1396           2 :                 break;
    1397           0 :             case 'L':
    1398           0 :                 if (readWord("LAND")) {
    1399           0 :                     BYTECODE_OP_BIN(LAND)
    1400           0 :                 } else if (readWord("LESS")) {
    1401           0 :                     BYTECODE_OP_BIN(LESS)
    1402           0 :                 } else if (readWord("LESSEQ")) {
    1403           0 :                     BYTECODE_OP_BIN(LESSEQ)
    1404           0 :                 } else if (readWord("LNOT")) {
    1405           0 :                     BYTECODE_OP_BIN(LNOT)
    1406           0 :                 } else if (readWord("LOAD")) {
    1407           0 :                     BYTECODE_OP_BIN(LOAD)
    1408           0 :                 } else if (readWord("LOR")) {
    1409           0 :                     BYTECODE_OP_BIN(LOR)
    1410           0 :                 } else couldRead = false;
    1411           0 :                 break;
    1412           2 :             case 'M':
    1413           2 :                 if (readWord("MINUS")) {
    1414           0 :                     BYTECODE_OP_BIN(MINUS)
    1415           2 :                 } else if (readWord("MOD")) {
    1416           0 :                     BYTECODE_OP_BIN(MOD)
    1417           2 :                 } else if (readWord("MUL")) {
    1418           2 :                     BYTECODE_OP_BIN(MUL)
    1419           0 :                 } else couldRead = false;
    1420           2 :                 break;
    1421           0 :             case 'N':
    1422           0 :                 if (readWord("NEQ")) {
    1423           0 :                     BYTECODE_OP_BIN(NEQ)
    1424           0 :                 } else couldRead = false;
    1425           0 :                 break;
    1426           0 :             case 'P':
    1427           0 :                 if (readWord("PLUS")) {
    1428           0 :                     BYTECODE_OP_BIN(PLUS)
    1429           0 :                 } else couldRead = false;
    1430           0 :                 break;
    1431           2 :             case 'R':
    1432           2 :                 if (readWord("READ")) {
    1433           1 :                     BYTECODE_OP_BIN(READ)
    1434           1 :                 } else if (readWord("RET")) {
    1435           1 :                     types.push_back(_LABEL_);
    1436           1 :                     BYTECODE_OP_BIN(RET)
    1437           0 :                 } else couldRead = false;
    1438           2 :                 break;
    1439           0 :             case 'S':
    1440           0 :                 if (readWord("STOP")) {
    1441           0 :                     BYTECODE_OP_BIN(STOP)
    1442           0 :                 } else couldRead = false;
    1443           0 :                 break;
    1444           0 :             case 'W':
    1445           0 :                 if (readWord("WRITE")) {
    1446           0 :                     BYTECODE_OP_BIN(WRITE)
    1447           0 :                 } else couldRead = false;
    1448           0 :                 break;
    1449             :             
    1450          15 :             default:
    1451          15 :                 couldRead = false;
    1452          15 :                 break;
    1453             :         }
    1454          27 :         if (!couldRead) {
    1455          16 :             int fieldSize = 1;
    1456          16 :             int p = c.pos;
    1457             :             try {
    1458          16 :                 types.push_back(constExpr(&fieldSize));
    1459           2 :             } catch (Obstacle & o) {
    1460           1 :                 revert(c.pos - p - 1);
    1461           1 :                 IdentTable * ident = IdTable.getIT(identificator());
    1462           1 :                 if (ident->isFunc()) {
    1463           1 :                     IdTable.pushType(_LABEL_);
    1464           1 :                     IdTable.pushVal( new int (ident->getOffset()) );
    1465           1 :                     IdentTable * label = IdTable.confirm();
    1466           1 :                     poliz.pushVal(label);
    1467           1 :                     types.push_back(_LABEL_);
    1468             :                 } else {
    1469           0 :                     poliz.pushVal(static_cast<IdentTable *>(ident->getVal()));
    1470           0 :                     types.push_back(ident->getType());
    1471             :                 }
    1472             :             }
    1473             :         }
    1474             : 
    1475          27 :         if ((c == ' ') || (c == '\n')) code >> c;
    1476          27 :     } while (c == ',');
    1477             : 
    1478           4 :     if (c != '}')
    1479           0 :         throw Obstacle(PROG_CLOSEBR);
    1480             :     
    1481           4 :     code >> c;
    1482           4 : }
    1483             : 
    1484           6 : void Parser::whileOp(void) {
    1485           6 :     IdTable.pushType(_LABEL_);
    1486           6 :     IdentTable * exit = IdTable.confirm();
    1487           6 :     exits.push(exit);
    1488             : 
    1489           6 :     if ((c == ' ') || (c == '\n')) code >> c;
    1490           6 :     if (c != '(')
    1491           0 :         throw Obstacle(BAD_PARAMS_OPBR);
    1492             : 
    1493           6 :     IdTable.pushType(_LABEL_);
    1494           6 :     IdTable.pushVal( new int (poliz.getSize()) );
    1495           6 :     IdentTable * condexpr = IdTable.confirm();
    1496           6 :     steps.push(condexpr);
    1497           6 :     code >> c;
    1498             : 
    1499           6 :     int fieldSize = 1;
    1500           6 :     type_t e2 = expr(&fieldSize); // условие продолжения
    1501             : 
    1502           6 :     if (e2 != _BOOLEAN_) throw Obstacle(BAD_IF);
    1503           5 :     poliz.pushOp(_NONE_, _BOOLEAN_, LNOT);
    1504           5 :     poliz.pushVal(exit);
    1505           5 :     poliz.pushOp(_BOOLEAN_, _LABEL_, JIT);
    1506             :     
    1507           5 :     if ((c == ' ') || (c == '\n')) code >> c;
    1508           5 :     if (c != ')')
    1509           0 :         throw Obstacle(BAD_PARAMS_CLBR);
    1510             : 
    1511           5 :     code >> c;
    1512           5 :     operation();  // тело цикла
    1513             : 
    1514           5 :     poliz.pushVal(condexpr);
    1515           5 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1516             : 
    1517           5 :     exit->setVal(new int (poliz.getSize()) );
    1518           5 :     exits.pop();
    1519           5 :     steps.pop();
    1520           5 : }
    1521           3 : void Parser::breakOp(void) {
    1522           3 :     if (exits.isEmpty())
    1523           1 :         throw Obstacle(BREAK_OUTSIDE_CYCLE);
    1524           2 :     poliz.pushVal(static_cast<IdentTable *>(exits.top()));
    1525           2 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1526           2 :     if (c != ';')
    1527           0 :         throw Obstacle(SEMICOLON);
    1528           2 :     code >> c;
    1529           2 : }
    1530             : 
    1531           2 : void Parser::continueOp(void) {
    1532           2 :     if (exits.isEmpty())
    1533           1 :         throw Obstacle(CONTINUE_OUTSIDE_CYCLE);
    1534           1 :     poliz.pushVal(static_cast<IdentTable *>(steps.top()));
    1535           1 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1536           1 :     if (c != ';')
    1537           0 :         throw Obstacle(SEMICOLON);
    1538           1 :     code >> c;
    1539           1 : }
    1540             : 
    1541           5 : void Parser::gotoOp(void) {
    1542           5 :     code >> c;
    1543           5 :     char * label = identificator();
    1544             :     IdentTable * labval;
    1545             :     try {
    1546           5 :         labval = IdTable.getIT(label, false);
    1547             :     }
    1548           3 :     catch(Obstacle & o) {
    1549             :         // До метки ещё не дошли, но это не повод расстраиваться!
    1550           3 :         labval = saveLabel(label, 0);
    1551             :     }
    1552             :     
    1553           5 :     if (labval->getType() != _LABEL_)
    1554           0 :         throw Obstacle(BAD_LABEL);
    1555             : 
    1556           5 :     code >> c;
    1557             : 
    1558           5 :     poliz.pushVal(labval);
    1559           5 :     poliz.pushOp(_NONE_, _LABEL_, JMP);
    1560           5 : }
    1561             : 
    1562          18 : void Parser::readOp(void) {
    1563          18 :     if ((c == ' ') || (c == '\n')) code >> c;
    1564          18 :     if (c != '(')
    1565           0 :         throw Obstacle(BAD_PARAMS_OPBR);
    1566             : 
    1567          18 :     code >> c;
    1568          18 :     char * operand = identificator();
    1569          18 :     IdentTable * it = IdTable.getIT(operand);
    1570          18 :     poliz.pushVal(it);
    1571          18 :     poliz.pushOp(_NONE_, it->getType(), READ);
    1572             : 
    1573          18 :     if ((c == ' ') || (c == '\n')) code >> c;
    1574          18 :     if (c != ')')
    1575           0 :         throw Obstacle(BAD_PARAMS_CLBR);
    1576             : 
    1577          18 :     code >> c;
    1578             : 
    1579          18 :     if (c != ';')
    1580           0 :         throw Obstacle(SEMICOLON);
    1581             : 
    1582          18 :     code >> c;
    1583          18 : }
    1584             : 
    1585          81 : void Parser::writeOp(void) {
    1586          81 :     if ((c == ' ') || (c == '\n')) code >> c;
    1587          81 :     if (c != '(')
    1588           0 :         throw Obstacle(BAD_PARAMS_OPBR);
    1589             : 
    1590          95 :     do {
    1591         176 :         code >> c;
    1592         176 :         int fieldSize = 1;
    1593         176 :         type_t exop = expr(&fieldSize);
    1594         171 :         poliz.pushOp(_NONE_, exop, WRITE);
    1595         171 :     } while (c == ',');
    1596             : 
    1597          76 :     poliz.pushOp(_NONE_, _NONE_, ENDL);
    1598             : 
    1599          76 :     if (c != ')')
    1600           0 :         throw Obstacle(BAD_PARAMS_CLBR);
    1601             : 
    1602          76 :     code >> c;
    1603             : 
    1604          76 :     if (c != ';')
    1605           0 :         throw Obstacle(SEMICOLON);
    1606             : 
    1607          76 :     code >> c;
    1608          76 : }
    1609             : 
    1610          29 : void Parser::giveBIN(const char * filename, bool optimize, bool printPoliz, bool verbose) {
    1611          29 :     bin.open(filename, std::ios_base::binary | std::ios_base::out);
    1612          29 :     int x = 0;
    1613          29 :     bin.write((char*)&x, sizeof(int)); // Сюда запишем адрес начала команд
    1614             : 
    1615          29 :     IdentTable * ITp = &IdTable;
    1616             : 
    1617          29 :     if (optimize) {
    1618          29 :         Optimizer opt(&IdTable, &poliz, verbose);
    1619          29 :         ITp = opt.optimize();
    1620             :     }
    1621             : 
    1622          29 :     if (printPoliz) {
    1623           0 :         ITp->repr();
    1624           0 :         poliz.repr();
    1625           0 :         std::cout << std::endl;
    1626             :     }
    1627             : 
    1628         358 :     while (ITp->next != nullptr) {
    1629         329 :         ITp->setOffset((int)bin.tellp());
    1630         329 :         ITp->writeValToStream(bin);
    1631         329 :         ITp = ITp->next;
    1632             :     }
    1633             : 
    1634          29 :     int progStart = bin.tellp();
    1635          29 :     int b = poliz.getSize();
    1636          29 :     op_t * prog = poliz.getProg();
    1637          29 :     bool * execBit = poliz.getEB();
    1638        1344 :     for (int i = 0; i < b; i++) {
    1639        1315 :         if (execBit[i]) {
    1640         660 :             int tempint1 = (int)prog[i];
    1641         660 :             bin.write((char*)&tempint1, sizeof(int));
    1642             :         } else {
    1643         655 :             int tempint2 = IT_FROM_POLIZ(poliz, i)->getOffset();
    1644         655 :             bin.write((char*)&tempint2, sizeof(int));
    1645             :         }
    1646        1315 :         bin.write((char*)&execBit[i], sizeof(bool));
    1647             :     }
    1648          29 :     bin.seekp(0, std::ios_base::beg);
    1649          29 :     bin.write((char*)&progStart, sizeof(int));
    1650             : 
    1651          29 :     bin.close();
    1652          29 : }
    1653             : 
    1654        4920 : void Parser::revert(int x) {
    1655        4920 :     code.seekg((int)code.tellg() - x - 1);
    1656        4920 :     code >>= c;
    1657        4920 :     c.pos -= x + 1;
    1658        4920 : }

Generated by: LCOV version 1.14