Как объяснялось ранее, очень легко применить макрос препроцессора для эксперимента с циклом repeat/until. Транслятор реализует его как пример или модель для любого другого типа цикла, с которым вы захотите поэкспериментировать. Транслятор для экспериментальных конструкций на С++ в листинге 4.1 приведен полный код транслятора. Для того чтобы им воспользоваться, сохраните код в файле trans.cpp. iJJjCTMHr 4.1. Транслятор для экспериментальных расширений языка С++ •include <iostream> •include <fstream> •include <cctype> #include <cstring> #include <string> using namespace std; // Прототипы функций, обеспечивающих обработку // ключевых слов расширений. void foreach(); void cases(); void repeat(); void until(); void typeofO; // Прототипы для разметки (tokenizing) входного файла, bool get token (string &tok) ,-void skipspaces (); // Строка-заполнитель для отступов, string indent = ""; // Входной и выходной файловые потоки, ifstream fin; ofstream fout; // Класс исключений для синтаксических ошибок, class SyntaxExc { •string what; public : SyntaxExc(char *e) { what = string(e); } string geterrorO { return what; } }; int main(int argc, char *argv[]) { string token; if(argc != 3) { cout « "Usage: ep <input file> <output file>\n" return 1; } fin.open(argv[l]); if(!fin) { cout « "Cannot open " « argv[l] « endl; return 1; } fout.open(argv[2]); iЈ(!fout) { cout « "Cannot open " « argv[2] « endl; return 1; } // Записывает заголовок. fout « "// Translated from an .exp source file.\n" try { // Главный цикл трансляции, while(gettoken(token)) { // Пропускает комментарии //. if(token == "//") { do { fout « token; gettoken(token); } while(token.find('\n') == string::npos); fout « token; } // Пропускает комментарии /*. else if(token == "/*") { do { fout « token; gettoken(token); } while(token != "*/"); fout « token; } // Пропускает строку в кавычках. else if(token == n\aa) { do { fout « token; gettoken(token),-} while(token != n\"") ; fout « token; } else if (token == "foreach") foreachO; else if(token == "cases") cases(); else if(token == "repeat") repeat(); else if (token == "until") until(); else if (token == "typeof") typeofO; else fout « token; } } catch(SyntaxExc exc) { cout « exc.geterrorO « endl; return 1; } return 0; } // Получает следующую лексему из входного потока, bool gettoken(string &tok) { char ch; char ch2; static bool tracklndent = true; tok = "";• ch = fin.get(); // Ищет EOF и возвращает false, если EOF найден Јf(!fin) return false; II Читает пробелы, if (isspace(ch)) { while(isspace(ch)) { tok += ch; // Переустанавливает счетчик отступа (indent counter) // для каждой новой строки. if(ch == '\n') { indent = ""; tracklndent = true; } else if(tracklndent) indent += ch; ch = fin.getO ; } fin. putback (ch) ; return true; } // Перестает отслеживать отступ, обнаружив // первый отличный от пробела символ в строке. tracklndent = false; // Считывает идентификатор или ключевое слово. if(isaipha(ch) || ch=='_') { While(isalpha(ch) || isdigit(ch) || ch=='_') { tok f= ch; ch = fin.getO ; } fin.putback(ch) ; return true; } 11 Считывает число. if(isdigit(ch)) { While(isdigit(ch) || ch=='.' || tolower(ch) == 'e' || ch == '-' I I ch ==' + ') { tok += ch; ch = fin.get(); } fin.putback(ch); return true; } // Ищет символьную комбинацию \" if(ch == -W) { ch2 = fin.get() ; if(ch2 == "") { tok += ch;. tok += ch2; ch = fin.getO ; } else fin.putback(ch2) ; } // Ищет символ '"' if (ch == 'V' ) { ch2 = fin.getO ; if (ch2 =='"•){ tok += ch; tok += ch2; return true; } else fin. pu tback (ch2) ; } // Ищет начало символов комментария, if(ch == ¦/') { tok' += ch; ch = fin.getO; if(ch == '/' || ch == '*') { tok += ch; } else fin.putback(ch); return true; } If Ищет конец символов комментария. if(ch == '*') { tok += ch; ch = fin.getO ; if(ch == '/') { tok += ch; } else fin.putback(ch); return true; } tok += ch; return true; ) // Транслирует цикл foreach. void foreach () { string token; string varname; string arrayname; char forvarname[5] = "_i"; static char counter[2] = "a"; // Создает управляющую переменную цикла для генерируемого // цикла for. strcat(forvarname, counter); counter [ 0]++; II В файле может быть только 26 циклов foreach, так как число II генерируемых управляющих переменных цикла ограничено II Диапазоном от _ia до _iz. При желании это можно изменить, if(counter[0] > 'z') throw SyntaxExc("Too many foreach loops."); fout « "int " « forvarname « " = 0;\n"; // Записывает начало генерируемого цикла for. fout « indent « "for("; skipspaces(); // Считывает "(" gettoken(token); if(token[0] != ¦(') throw SyntaxExc("( expected in foreach."); skipspaces(); // Получает тип переменной цикла foreach. gettoken(token); fout « token « " "; skipspaces(); // Читает и сохраняет имя переменной цикла foreach. gettoken(token); varname = token; skipspaces(); // Читает "in", gettoken(token); if(token != "in") throw SyntaxExc("in expected in foreach."); skipspaces(); // Читает имя массива, gettoken(token); arrayname = token; fout « varname « " = " « arrayname « "[0];\n"; // Конструирует результирующую строку. fout « indent + " " « forvarname « " < " « " ( (sizeof " « token « ")/" « "(sizeof " « token « "[0]));\n"; fout « indent + " " « forvarname « "++, " « varname « " = " « arrayname « " [" « forvarname « "])" ; skipspaces () ; // Считьшает ")". gettoken(token); if (token [0] != ¦) ') throw SyntaxExc(") expected in foreach."); } // Транслирует оператор cases, void cases () { string token; int start, end; skipspaces () ; // Получает начальное значение. gettoken (token) ; if (isdigit(token[0])) { // получена константа int start = atoi(token.c_str()); } else if (token [0] == ,\") { // получена константа char gettoken(token); start = (int) token[0]; // отбрасывает закрывающий * (апостроф) gettoken(token); if (token [0] != 'V ') throw SyntaxExc("' expected in cases."); } else throw SyntaxExc("Constant expected in cases."); skipspaces(); // Читает и отбрасывет J,to". gettoken{token); if(token != "to") throw SyntaxExc("to expected in cases."); skipspaces () ; // Получает конечное значение. gettoken(token); if(isdigit(token[0])) { // Получена константа int end = atoi(token.c_str()); } else if (token[0] == '\") { // Получена константа char gettoken(token); end =s (int) token[0]; // Отбрасывает закрывающий ' gettoken(token); if(token[0] != 'V ' ) throw SyntaxExc("' expected in cases .") ; } else throw SyntaxExc("Constant expected in cases.") skipspaces(); // Читает и отбрасывает gettoken(token); if(token != ":") throw SyntaxExc(": expected in cases.") ; 11 Генерирует стопочные case-операторы, fout « "case " « start « ":\n"; • for(int i = start+1 ; i <= end; i++) ( fout « indent « "case " « i « ":"; if(i != end) fout « endl; } } // Транслирует repeat, void repeat() { fout « " do" ; } // Транслирует until, void until () { string token; int parencount = 1; fout « "while" ; skipspaces (); // Читает и запоминает "(". gettoken (token) ; if(token != "(") throw SyntaxExc("( expected in typeof ."); fout « " (" ; // Начинает цикл while, заменяя на противоположное //и заключая в скобки условное выражение. ¦ fOUt « "!("; // Теперь читает выражение, do { i f(!gettoken(token)) throw SyntaxExc("Unexpected EOF encountered."); if(token == "(") parencount++; if(token == ")") parencount—; , fout « token; } while(parencount > 0); fout « ")"; } // Транслирует оператор typeof. void typeof() { string token; string temp; fout « "typeld("; skipspaces(); gettoken(token); do { temp = token; if(Igettoken(token)) throw SyntaxExc("Unexpected EOF encountered."); if(token != "same") fout « temp; } while(token != "same"); skipspaces(); gettoken(token); if(token != "as") throw SyntaxExc("as expected."); fout « ") == typeid("; skipspaces(); do { if(!gettoken(token)) throw SyntaxExc("Unexpected EOF encountered."); fout « token; } while(token !=")"); fout « ") " ; } ^id skipspaces О { char ch; do { ch = fin.getO ; } while(isspace(ch)); fin.putback(ch); }
|