Главная arrow С++ (часть 3) arrow Цикл repeat/until

Цикл repeat/until

Как объяснялось ранее, очень легко применить макрос препроцессора для эксперимента с циклом 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);
}