import java.io.*;
// Компилятор языка "О"
public class Main{
static void Init() {
Text.Reset();
if( !Text.Ok )
Error.
Message(Text.
Message); Scan.Init();
Gen.Init();
}
static void Done() {
Text.Close();
}
public static void main
(String[] args
) { System.
out.
println("\nКомпилятор языка О"); if( args.length == 0 )
Location.Path = null;
else
Location.Path = args[0];
Init(); // Инициализация
Pars.Compile(); // Компиляция
OVM.Run(); // Выполнение
Done(); // Завершение
}
}
// Текущая позиция в исходном тексте
class Location {
static int Line; // Номер строки static int Pos; // Номер символа в строке
static int LexPos; // Позиция начала лексемы
static String Path
; // Путь к файлу }
// Обработка ошибок
static void Message
(String Msg
) { int ELine
= Location.
Line; while( Text.Ch != Text.chEOL && Text.Ch != Text.chEOT )
Text.NextCh();
if( Text.
Ch == Text.
chEOT ) System.
out.
println(); for( int i = 1; i < Location.LexPos; i++ )
"(Строка " + ELine + ") Ошибка: " + Msg
);
System.
out.
print("Нажмите ВВОД"); try{ while( System.
in.
read() != '\n' ); } }
static void Expected
(String Msg
) { Message("Ожидается " + Msg);
}
static void Warning
(String Msg
) { System.
out.
println("Предупреждение: " + Msg
); }
}
// Генератор кода
class Gen {
static int PC;
static void Init() {
PC = 0;
}
static void Cmd(int Cmd) {
if( PC < OVM.MEMSIZE )
OVM.M[PC++] = Cmd;
else
Error.
Message("Недостаточно памяти для кода"); }
static void Fixup(int A) {
while( A > 0 ) {
int temp = OVM.M[A-2];
OVM.M[A-2] = PC;
A = temp;
}
}
static void Abs() {
Cmd(OVM.cmDup);
Cmd(0);
Cmd(PC+3);
Cmd(OVM.cmIfGE);
Cmd(OVM.cmNeg);
}
static void Min() {
Cmd(OVM.cmNeg);
Cmd(1);
Cmd(OVM.cmSub);
}
static void Odd() {
Cmd(2);
Cmd(OVM.cmMod);
Cmd(1);
Cmd(0); // Адрес перехода вперед
Cmd(OVM.cmIfNE);
}
static void Const(int C) {
if ( C < 0 )
Cmd(OVM.cmNeg);
}
static void Comp(int Lex) {
Cmd(0); // Адрес перехода вперед
switch( Lex ) {
case Scan.lexEQ : Cmd(OVM.cmIfNE); break;
case Scan.lexNE : Cmd(OVM.cmIfEQ); break;
case Scan.lexLE : Cmd(OVM.cmIfGT); break;
case Scan.lexLT : Cmd(OVM.cmIfGE); break;
case Scan.lexGE : Cmd(OVM.cmIfLT); break;
case Scan.lexGT : Cmd(OVM.cmIfLE); break;
}
}
static void Addr(Obj X) {
Cmd(X.Val); // В текущую ячейку адрес предыдущей + 2
X.Val = PC+1; // Адрес+2 = PC+1
}
static void AllocateVariables() {
Obj VRef; // Ссылка на переменную в таблице имен
VRef = Table.FirstVar(); // Найти первую переменную
while( VRef != null ) {
if ( VRef.Val == 0 )
"Переменная " + VRef.
Name + " не используется" );
else if( PC < OVM.MEMSIZE ) {
Fixup(VRef.Val); // Адресная привязка переменной
PC++;
}
else
Error.
Message("Недостаточно памяти для переменных"); VRef = Table.NextVar(); // Найти следующую переменную
}
}
}
// Виртуальная машина
class OVM {
static final int MEMSIZE = 8*1024;
static final int
cmStop = -1,
cmAdd = -2,
cmSub = -3,
cmMult = -4,
cmDiv = -5,
cmMod = -6,
cmNeg = -7,
cmLoad = -8,
cmSave = -9,
cmDup = -10,
cmDrop = -11,
cmSwap = -12,
cmOver = -13,
cmGOTO = -14,
cmIfEQ = -15,
cmIfNE = -16,
cmIfLE = -17,
cmIfLT = -18,
cmIfGE = -19,
cmIfGT = -20,
cmIn = -21,
cmOut = -22,
cmOutLn = -23;
static int M[] = new int[MEMSIZE];
static void readln() {
try { while( System.
in.
read() != '\n' ); } }
static int ReadInt() {
return (int)input.nval;
}
static void Run() {
int PC = 0;
int SP = MEMSIZE;
int Cmd;
int Buf;
loop: for (;;)
if ( (Cmd = M[PC++]) >= 0 )
M[--SP] = Cmd;
else
switch( Cmd ) {
case cmAdd:
SP++; M[SP] += M[SP-1];
break;
case cmSub:
SP++; M[SP] -= M[SP-1];
break;
case cmMult:
SP++; M[SP] *= M[SP-1];
break;
case cmDiv:
SP++; M[SP] /= M[SP-1];
break;
case cmMod:
SP++; M[SP] %= M[SP-1];
break;
case cmNeg:
M[SP] = -M[SP];
break;
case cmLoad:
M[SP] = M[M[SP]];
break;
case cmSave:
M[M[SP+1]] = M[SP];
SP += 2;
break;
case cmDup:
SP--; M[SP] = M[SP+1];
break;
case cmDrop:
SP++;
break;
case cmSwap:
Buf = M[SP]; M[SP] = M[SP+1]; M[SP+1] = Buf;
break;
case cmOver:
SP--; M[SP] = M[SP+2];
break;
case cmGOTO:
PC = M[SP++];
break;
case cmIfEQ:
if ( M[SP+2] == M[SP+1] )
PC = M[SP];
SP += 3;
break;
case cmIfNE:
if ( M[SP+2] != M[SP+1] )
PC = M[SP];
SP += 3;
break;
case cmIfLE:
if ( M[SP+2] <= M[SP+1] )
PC = M[SP];
SP += 3;
break;
case cmIfLT:
if ( M[SP+2] < M[SP+1] )
PC = M[SP];
SP += 3;
break;
case cmIfGE:
if ( M[SP+2] >= M[SP+1] )
PC = M[SP];
SP += 3;
break;
case cmIfGT:
if ( M[SP+2] > M[SP+1] )
PC = M[SP];
SP += 3;
break;
case cmIn:
M[--SP] = ReadInt();
break;
case cmOut:
int w
= M
[SP
] - (new Integer(M
[SP
+1])).
toString().length();
for( int i = 1; i <= w; i++ )
SP += 2;
break;
case cmOutLn:
break;
case cmStop:
break loop;
default:
System.
out.
println("Недопустимый код операции"); break loop;
}
if( SP < MEMSIZE )
System.
out.
println("Код возврата " + M
[SP
]); }
}
// Распознаватель
class Pars {
static final int
spABS = 1,
spMAX = 2,
spMIN = 3,
spDEC = 4,
spODD = 5,
spHALT = 6,
spINC = 7,
spInOpen = 8,
spInInt = 9,
spOutInt = 10,
spOutLn = 11;
static void Check
(int L,
String M
) { if( Scan.Lex != L )
else
Scan.NextLex();
}
// ["+" | "-"] (Число | Имя)
static int ConstExpr() {
int v = 0;
Obj X;
int Op;
Op = Scan.lexPlus;
if( Scan.Lex == Scan.lexPlus ||
Scan.Lex == Scan.lexMinus )
{
Op = Scan.Lex;
Scan.NextLex();
}
if( Scan.Lex == Scan.lexNum ) {
v = Scan.Num;
Scan.NextLex();
}
else if( Scan.Lex == Scan.lexName ) {
X
= Table.
Find(Scan.
Name); if( X.Cat == Table.catGuard )
"Нельзя определять константу через себя"
);
else if( X.Cat != Table.catConst )
Error.
Expected( "имя константы" ); else {
v = X.Val;
Scan.NextLex();
}
}
else
Error.
Expected( "константное выражение" ); if( Op == Scan.lexMinus )
return -v;
return v;
}
// Имя "=" КонстВыраж
static void ConstDecl() {
Obj ConstRef; // Ссылка на имя в таблице
ConstRef
= Table.
NewName(Scan.
Name, Table.
catGuard); Scan.NextLex();
Check(Scan.lexEQ, "\"=\"");
ConstRef.Val = ConstExpr();
ConstRef.Typ = Table.typInt; //Констант других типов нет
ConstRef.Cat = Table.catConst;
}
static void ParseType() {
Obj TypeRef;
if( Scan.Lex != Scan.lexName )
else {
TypeRef
= Table.
Find(Scan.
Name); if( TypeRef.Cat != Table.catType )
Error.
Expected("имя типа"); else if( TypeRef.Typ != Table.typInt )
Error.
Expected("целый тип"); Scan.NextLex();
}
}
// Имя {"," Имя} ":" Тип
static void VarDecl() {
Obj NameRef;
if( Scan.Lex != Scan.lexName )
else {
NameRef
= Table.
NewName(Scan.
Name, Table.
catVar); NameRef.Typ = Table.typInt;
Scan.NextLex();
}
while( Scan.Lex == Scan.lexComma ) {
Scan.NextLex();
if( Scan.Lex != Scan.lexName )
else {
NameRef
= Table.
NewName(Scan.
Name, Table.
catVar ); NameRef.Typ = Table.typInt;
Scan.NextLex();
}
}
Check(Scan.lexColon, "\":\"");
ParseType();
}
// { CONST {ОбъявлКонст ";"} | VAR {ОбъявлПерем ";"} }
static void DeclSeq() {
while( Scan.Lex == Scan.lexCONST ||
Scan.Lex == Scan.lexVAR )
{
if( Scan.Lex == Scan.lexCONST ) {
Scan.NextLex();
while( Scan.Lex == Scan.lexName ) {
ConstDecl(); //Объявление константы
Check(Scan.lexSemi, "\";\"");
}
}
else {
Scan.NextLex(); // VAR
while( Scan.Lex == Scan.lexName ) {
VarDecl(); //Объявление переменных
Check(Scan.lexSemi, "\";\"");
}
}
}
}
static void IntExpression() {
if( Expression() != Table.typInt )
Error.
Expected("выражение целого типа"); }
static int StFunc(int F) {
switch( F ) {
case spABS:
IntExpression();
Gen.Abs();
return Table.typInt;
case spMAX:
ParseType();
return Table.typInt;
case spMIN:
ParseType();
Gen.Min();
return Table.typInt;
case spODD:
IntExpression();
Gen.Odd();
return Table.typBool;
}
return Table.typNone; // Чтоб не было предупреждений
}
static int Factor() {
Obj X;
int T = 0; // Чтоб не было предупреждений
if( Scan.Lex == Scan.lexName ) {
if( (X
= Table.
Find(Scan.
Name)).
Cat == Table.
catVar ) { Gen.Addr(X); //Адрес переменной
Gen.Cmd(OVM.cmLoad);
Scan.NextLex();
return X.Typ;
}
else if( X.Cat == Table.catConst ) {
Gen.Const(X.Val);
Scan.NextLex();
return X.Typ;
}
else if( X.Cat == Table.catStProc &&
X.Typ != Table.typNone )
{
Scan.NextLex();
Check(Scan.lexLPar, "\"(\"");
T = StFunc(X.Val);
Check(Scan.lexRPar, "\")\"");
}
else
"переменная, константа или процедура-функции"
);
}
else if( Scan.Lex == Scan.lexNum ) {
Gen.Const(Scan.Num);
Scan.NextLex();
return Table.typInt;
}
else if( Scan.Lex == Scan.lexLPar ) {
Scan.NextLex();
T = Expression();
Check(Scan.lexRPar, "\")\"");
}
else
Error.
Expected("имя, число или \"(\""); return T;
}
static int Term() {
int Op;
int T = Factor();
if( Scan.Lex == Scan.lexMult || Scan.Lex == Scan.lexDIV
|| Scan.Lex == Scan.lexMOD )
{
if( T != Table.typInt )
"Несоответствие операции типу операнда"
);
do {
Op = Scan.Lex;
Scan.NextLex();
if( (T = Factor()) != Table.typInt )
Error.
Expected("выражение целого типа"); switch( Op ) {
case Scan.lexMult: Gen.Cmd(OVM.cmMult); break;
case Scan.lexDIV: Gen.Cmd(OVM.cmDiv); break;
case Scan.lexMOD: Gen.Cmd(OVM.cmMod); break;
}
} while( Scan.Lex == Scan.lexMult ||
Scan.Lex == Scan.lexDIV ||
Scan.Lex == Scan.lexMOD );
}
return T;
}
// ["+"|"-"] Слагаемое {ОперСлож Слагаемое}
static int SimpleExpr() {
int T;
int Op;
if( Scan.Lex == Scan.lexPlus ||
Scan.Lex == Scan.lexMinus )
{
Op = Scan.Lex;
Scan.NextLex();
if( (T = Term()) != Table.typInt )
Error.
Expected("выражение целого типа"); if( Op == Scan.lexMinus )
Gen.Cmd(OVM.cmNeg);
}
else
T = Term();
if( Scan.Lex == Scan.lexPlus ||
Scan.Lex == Scan.lexMinus )
{
if( T != Table.typInt )
"Несоответствие операции типу операнда"
);
do {
Op = Scan.Lex;
Scan.NextLex();
if( (T = Term()) != Table.typInt )
Error.
Expected("выражение целого типа"); switch(Op) {
case Scan.lexPlus: Gen.Cmd(OVM.cmAdd); break;
case Scan.lexMinus: Gen.Cmd(OVM.cmSub); break;
}
} while( Scan.Lex == Scan.lexPlus ||
Scan.Lex == Scan.lexMinus );
}
return T;
}
// ПростоеВыраж [Отношение ПростоеВыраж]
static int Expression() {
int Op;
int T = SimpleExpr();
if( Scan.Lex == Scan.lexEQ || Scan.Lex == Scan.lexNE ||
Scan.Lex == Scan.lexGT || Scan.Lex == Scan.lexGE ||
Scan.Lex == Scan.lexLT || Scan.Lex == Scan.lexLE )
{
Op = Scan.Lex;
if( T != Table.typInt )
"Несоответствие операции типу операнда"
);
Scan.NextLex();
if( (T = SimpleExpr()) != Table.typInt )
Error.
Expected("выражение целого типа"); Gen.Comp(Op); //Генерация условного перехода
T = Table.typBool;
} //иначе тип равен типу первого простого выражения
return T;
}
// Переменная = Имя
static void Variable() {
Obj X;
if( Scan.Lex != Scan.lexName )
else {
if( (X
= Table.
Find(Scan.
Name)).
Cat != Table.
catVar ) Error.
Expected("имя переменной"); Gen.Addr(X);
Scan.NextLex();
}
}
static void StProc(int P) {
switch( P ) {
case spDEC:
Variable();
Gen.Cmd(OVM.cmDup);
Gen.Cmd(OVM.cmLoad);
if( Scan.Lex == Scan.lexComma ) {
Scan.NextLex();
IntExpression();
}
else
Gen.Cmd(1);
Gen.Cmd(OVM.cmSub);
Gen.Cmd(OVM.cmSave);
return;
case spINC:
Variable();
Gen.Cmd(OVM.cmDup);
Gen.Cmd(OVM.cmLoad);
if( Scan.Lex == Scan.lexComma ) {
Scan.NextLex();
IntExpression();
}
else
Gen.Cmd(1);
Gen.Cmd(OVM.cmAdd);
Gen.Cmd(OVM.cmSave);
return;
case spInOpen:
// Пусто ;
return;
case spInInt:
Variable();
Gen.Cmd(OVM.cmIn);
Gen.Cmd(OVM.cmSave);
return;
case spOutInt:
IntExpression();
Check(Scan.lexComma , "\",\"");
IntExpression();
Gen.Cmd(OVM.cmOut);
return;
case spOutLn:
Gen.Cmd(OVM.cmOutLn);
return;
case spHALT:
Gen.Const(ConstExpr());
Gen.Cmd(OVM.cmStop);
return;
}
}
static void BoolExpression() {
if( Expression() != Table.typBool )
Error.
Expected("логическое выражение"); }
// Переменная "=" Выраж
static void AssStatement() {
Variable();
if( Scan.Lex == Scan.lexAss ) {
Scan.NextLex();
IntExpression();
Gen.Cmd(OVM.cmSave);
}
else
Error.
Expected("\":=\""); }
// Имя ["(" // Выраж | Переменная ")"]
static void CallStatement(int sp) {
Check(Scan.lexName, "имя процедуры");
if( Scan.Lex == Scan.lexLPar ) {
Scan.NextLex();
StProc(sp);
Check( Scan.lexRPar, "\")\"" );
}
else if( sp == spOutLn || sp == spInOpen )
StProc(sp);
else
}
static void IfStatement() {
int CondPC;
int LastGOTO;
Check(Scan.lexIF, "IF");
LastGOTO = 0; //Предыдущего перехода нет
BoolExpression();
CondPC = Gen.PC; //Запомн. положение усл. перехода
Check(Scan.lexTHEN, "THEN");
StatSeq();
while( Scan.Lex == Scan.lexELSIF ) {
Gen.Cmd(LastGOTO); //Фиктивный адрес, указывающий
Gen.Cmd(OVM.cmGOTO); //на место предыдущего перехода
LastGOTO = Gen.PC; //Запомнить место GOTO
Scan.NextLex();
Gen.Fixup(CondPC); //Зафикс. адрес условного перехода
BoolExpression();
CondPC = Gen.PC; //Запомн. положение усл. перехода
Check(Scan.lexTHEN, "THEN");
StatSeq();
}
if( Scan.Lex == Scan.lexELSE ) {
Gen.Cmd(LastGOTO); //Фиктивный адрес, указывающий
Gen.Cmd(OVM.cmGOTO); //на место предыдущего перехода
LastGOTO = Gen.PC; //Запомнить место последнего GOTO
Scan.NextLex();
Gen.Fixup(CondPC); //Зафикс. адрес условного перехода
StatSeq();
}
else
Gen.Fixup(CondPC); //Если ELSE отсутствует
Check( Scan.lexEND, "END" );
Gen.Fixup(LastGOTO); //Направить сюда все GOTO
}
static void WhileStatement() {
int WhilePC = Gen.PC;
Check(Scan.lexWHILE, "WHILE");
BoolExpression();
int CondPC = Gen.PC;
Check(Scan.lexDO, "DO");
StatSeq();
Check(Scan.lexEND, "END");
Gen.Cmd(WhilePC);
Gen.Cmd(OVM.cmGOTO);
Gen.Fixup(CondPC);
}
Obj X;
if( Scan.Lex == Scan.lexName ) {
if( (X
=Table.
Find(Scan.
Name)).
Cat == Table.
catModule ) {
Scan.NextLex();
Check(Scan.lexDot, "\".\"");
if( Scan.Lex == Scan.lexName &&
Scan.NAMELEN
)
X
= Table.
Find( X.
Name + "." + Scan.
Name); else
}
if( X.Cat == Table.catVar )
AssStatement(); //Присваивание
else if( X.Cat == Table.catStProc &&
X.Typ == Table.typNone
)
CallStatement(X.Val); //Вызов процедуры
else
"обозначение переменной или процедуры"
);
}
else if( Scan.Lex == Scan.lexIF )
IfStatement();
else if( Scan.Lex == Scan.lexWHILE )
WhileStatement();
// иначе пустой оператор
}
// Оператор {";" Оператор}
static void StatSeq() {
while( Scan.Lex == Scan.lexSemi ) {
Scan.NextLex();
}
}
static void ImportName() {
if( Scan.Lex == Scan.lexName ) {
Table.
NewName(Scan.
Name, Table.
catModule); if( Scan.
Name.
compareTo("In") == 0 ) { Table.Enter("In.Open",
Table.catStProc, Table.typNone, spInOpen);
Table.Enter("In.Int",
Table.catStProc, Table.typNone, spInInt);
}
else if( Scan.
Name.
compareTo("Out") == 0 ) { Table.Enter("Out.Int",
Table.catStProc, Table.typNone, spOutInt);
Table.Enter("Out.Ln",
Table.catStProc, Table.typNone, spOutLn);
}
else
Error.
Message("Неизвестный модуль"); Scan.NextLex();
}
else
Error.
Expected("имя импортируемого модуля"); }
// IMPORT Имя { "," Имя } ";"
static void Import() {
Check(Scan.lexIMPORT, "IMPORT");
ImportName(); //Обработка имени импортируемого модуля
while( Scan.Lex == Scan.lexComma ) {
Scan.NextLex();
ImportName(); //Обработка имени импортируемого модуля
}
Check(Scan.lexSemi, "\";\"");
}
// MODULE Имя ";" [Импорт] ПослОбъявл [BEGIN ПослОператоров]
// END Имя "."
static void Module() {
Obj ModRef; //Ссылка на имя модуля в таблице
Check(Scan.lexMODULE, "MODULE");
if( Scan.Lex != Scan.lexName )
Error.
Expected("имя модуля"); //Имя модуля - в таблицу имен
ModRef
= Table.
NewName(Scan.
Name, Table.
catModule); Scan.NextLex();
Check(Scan.lexSemi, "\";\"");
if( Scan.Lex == Scan.lexIMPORT )
Import();
DeclSeq();
if( Scan.Lex == Scan.lexBEGIN ) {
Scan.NextLex();
StatSeq();
}
Check(Scan.lexEND, "END");
//Сравнение имени модуля и имени после END
if( Scan.Lex != Scan.lexName )
Error.
Expected("имя модуля"); else if( Scan.
Name.
compareTo(ModRef.
Name) != 0 ) "имя модуля \"" + ModRef.
Name + "\"" );
else
Scan.NextLex();
if( Scan.Lex != Scan.lexDot )
Gen.Cmd(0); // Код возврата
Gen.Cmd(OVM.cmStop); // Команда останова
Gen.AllocateVariables(); // Размещение переменных
}
static void Compile() {
Table.Init();
Table.OpenScope(); //Блок стандартных имен
Table.Enter("ABS",
Table.catStProc, Table.typInt, spABS);
Table.Enter("MAX",
Table.catStProc, Table.typInt, spMAX);
Table.Enter("MIN",
Table.catStProc, Table.typInt, spMIN);
Table.Enter("DEC",
Table.catStProc, Table.typNone, spDEC);
Table.Enter("ODD",
Table.catStProc, Table.typBool, spODD);
Table.Enter("HALT",
Table.catStProc, Table.typNone, spHALT);
Table.Enter("INC",
Table.catStProc, Table.typNone, spINC);
Table.Enter("INTEGER",
Table.catType, Table.typInt, 0);
Table.OpenScope(); //Блок модуля
Module();
Table.CloseScope(); //Блок модуля
Table.CloseScope(); //Блок стандартных имен
System.
out.
println("\nКомпиляция завершена"); }
}
// Лексический анализатор
class Scan {
static int NAMELEN = 31; // Наибольшая длина имени
final static int
lexNone = 0,
lexName = 1, lexNum = 2,
lexMODULE = 3, lexIMPORT = 4,
lexBEGIN = 5, lexEND = 6,
lexCONST = 7, lexVAR = 8,
lexWHILE = 9, lexDO = 10,
lexIF = 11, lexTHEN = 12,
lexELSIF = 13, lexELSE = 14,
lexMult = 15, lexDIV = 16, lexMOD = 17,
lexPlus = 18, lexMinus = 19,
lexEQ = 20, lexNE = 21,
lexLT = 22, lexLE = 23,
lexGT = 24, lexGE = 25,
lexDot = 26, lexComma = 27, lexColon = 28,
lexSemi = 29, lexAss = 30,
lexLPar = 31, lexRPar = 32,
lexEOT = 33;
// Текущая лексема
static int Lex;
// Строковое значение имени
// Значение числовых литералов
static int Num;
private static int KWNUM = 34;
private static int nkw = 0;
static private class Item {
int Lex;
}
private static Item[] KWTable = new Item[KWNUM];
private static void EnterKW
(String Name,
int Lex
) { (KWTable
[nkw
] = new Item
()).
Word = new String(Name); // !! KWTable[nkw++].Lex = Lex;
}
private static int TestKW() {
for( int i = nkw - 1; i >= 0; i-- )
if( KWTable
[i
].
Word.
compareTo(Name) == 0 ) return KWTable[i].Lex;
return lexName;
}
private static void Ident() {
int i = 0;
Buf.setLength(0);
do {
if ( i++ < NAMELEN )
Buf.append((char)Text.Ch);
else
Error.
Message("Слишком длинное имя"); Text.NextCh();
} while( Character.
isLetterOrDigit((char)Text.
Ch) ); Lex = TestKW(); // Проверка на ключевое слово
}
private static void Number() { Lex = lexNum;
Num = 0;
do {
int d = Text.Ch - '0';
if( (Integer.
MAX_VALUE - d
)/10 >= Num
) Num = 10*Num + d;
else
Error.
Message("Слишком большое число"); Text.NextCh();
}
private static void Comment() {
Text.NextCh();
do {
while( Text.Ch != '*' && Text.Ch != Text.chEOT )
if( Text.Ch == '(' ) {
Text.NextCh();
if( Text.Ch == '*' )
Comment();
}
else
Text.NextCh();
if ( Text.Ch == '*' )
Text.NextCh();
} while( Text.Ch != ')' && Text.Ch != Text.chEOT );
if ( Text.Ch == ')' )
Text.NextCh();
else {
Location.LexPos = Location.Pos;
Error.
Message("Не закончен комментарий"); }
}
/*
private static void Comment() {
int Level = 1;
Text.NextCh();
do
if( Text.Ch == '*' ) {
Text.NextCh();
if( Text.Ch == ')' )
{ Level--; Text.NextCh(); }
}
else if( Text.Ch == '(' ) {
Text.NextCh();
if( Text.Ch == '*' )
{ Level++; Text.NextCh(); }
}
else //if ( Text.Ch <> chEOT )
Text.NextCh();
while( Level != 0 && Text.Ch != Text.chEOT );
if( Level != 0 ) {
Location.LexPos = Location.Pos;
Error.Message("Не закончен комментарий");
}
}
*/
static void NextLex() {
while(
Text.Ch == Text.chSPACE ||
Text.Ch == Text.chTAB ||
Text.Ch == Text.chEOL
)
Text.NextCh();
Location.LexPos = Location.Pos;
Ident();
else
switch( Text.Ch ) {
case ';':
Text.NextCh(); Lex = lexSemi;
break;
case ':':
Text.NextCh();
if( Text.Ch == '=' )
{ Text.NextCh(); Lex = lexAss; }
else
Lex = lexColon;
break;
case '.':
Text.NextCh(); Lex = lexDot;
break;
case ',':
Text.NextCh(); Lex = lexComma;
break;
case '=':
Text.NextCh(); Lex = lexEQ;
break;
case '#':
Text.NextCh(); Lex = lexNE;
break;
case '<':
Text.NextCh();
if( Text.Ch == '=' )
{ Text.NextCh(); Lex = lexLE; }
else
Lex = lexLT;
break;
case '>':
Text.NextCh();
if ( Text.Ch == '=' )
{ Text.NextCh(); Lex = lexGE; }
else
Lex = lexGT;
break;
case '(':
Text.NextCh();
if( Text.Ch == '*' )
{ Comment(); NextLex(); }
else
Lex = lexLPar;
break;
case ')':
Text.NextCh(); Lex = lexRPar;
break;
case '+':
Text.NextCh(); Lex = lexPlus;
break;
case '-':
Text.NextCh(); Lex = lexMinus;
break;
case '*':
Text.NextCh(); Lex = lexMult;
break;
case Text.chEOT:
Lex = lexEOT;
break;
default:
Error.
Message("Недопустимый символ"); }
}
static void Init() {
EnterKW("ARRAY", lexNone);
EnterKW("BY", lexNone);
EnterKW("BEGIN", lexBEGIN);
EnterKW("CASE", lexNone);
EnterKW("CONST", lexCONST);
EnterKW("DIV", lexDIV);
EnterKW("DO", lexDO);
EnterKW("ELSE", lexELSE);
EnterKW("ELSIF", lexELSIF);
EnterKW("END", lexEND);
EnterKW("EXIT", lexNone);
EnterKW("FOR", lexNone);
EnterKW("IF", lexIF);
EnterKW("IMPORT", lexIMPORT);
EnterKW("IN", lexNone);
EnterKW("IS", lexNone);
EnterKW("LOOP", lexNone);
EnterKW("MOD", lexMOD);
EnterKW("MODULE", lexMODULE);
EnterKW("NIL", lexNone);
EnterKW("OF", lexNone);
EnterKW("OR", lexNone);
EnterKW("POINTER", lexNone);
EnterKW("PROCEDURE", lexNone);
EnterKW("RECORD", lexNone);
EnterKW("REPEAT", lexNone);
EnterKW("RETURN", lexNone);
EnterKW("THEN", lexTHEN);
EnterKW("TO", lexNone);
EnterKW("TYPE", lexNone);
EnterKW("UNTIL", lexNone);
EnterKW("VAR", lexVAR);
EnterKW("WHILE", lexWHILE);
EnterKW("WITH", lexNone);
NextLex();
}
}
// Элемент таблицы имен
class Obj { // Тип записи таблицы имен
int Cat; // Категория имени
int Typ; // Тип
int Val; // Значение
Obj Prev; // Указатель на пред. имя
}
// Таблица имен
class Table {
// Категории имён
static final int
catConst = 1, catVar = 2,
catType = 3, catStProc = 4,
catModule = 5, catGuard = 6;
// Типы
static final int
typNone = 0, typInt = 1, typBool = 2;
private static Obj Top; //Указатель на вершину списка
private static Obj Bottom; //Указатель на конец списка
private static Obj CurrObj;
// Инициализация таблицы
static void Init() {
Top = null;
}
// Добавление элемента
static void Enter
(String N,
int C,
int T,
int V
) { Obj P = new Obj();
P.Cat = C;
P.Typ = T;
P.Val = V;
P.Prev = Top;
Top = P;
}
static void OpenScope() {
Enter("", catGuard, typNone, 0);
if ( Top.Prev == null )
Bottom = Top;
}
static void CloseScope() {
while( Top.Cat != catGuard ){
Top = Top.Prev;
}
Top = Top.Prev;
}
Obj obj = Top;
while(
obj.Cat != catGuard &&
)
obj = obj.Prev;
if ( obj.Cat == catGuard ) {
obj = new Obj();
obj.Cat = Cat;
obj.Val = 0;
obj.Prev = Top;
Top = obj;
}
else
Error.
Message("Повторное объявление имени"); return obj;
}
Obj obj;
for( obj
=Top
; obj.
Name.
compareTo(Name)!=0; obj
=obj.
Prev ); if( obj == Bottom )
Error.
Message("Необъявленное имя"); return obj;
}
static Obj FirstVar() {
CurrObj = Top;
return NextVar();
}
static Obj NextVar() {
Obj VRef;
while( CurrObj != Bottom && CurrObj.Cat != catVar )
CurrObj = CurrObj.Prev;
if( CurrObj == Bottom )
return null;
else {
VRef = CurrObj;
CurrObj = CurrObj.Prev;
return VRef;
}
}
}
// Драйвер исходного текста
class Text {
static final int TABSIZE = 3;
static final char chSPACE = ' '; // Пробел
static final char chTAB = '\t'; // Табуляция
static final char chEOL = '\n'; // Конец строки
static final char chEOT = '\0'; // Конец текста
static boolean Ok = false;
static String Message
= "Файл не открыт"; static int Ch = chEOT;
static void NextCh() {
try {
if( (Ch = f.read()) == -1 )
Ch = chEOT;
else if( Ch == '\n' ) {
Location.
Line++; Location.
Pos = 0; Ch
= chEOL
; }
else if( Ch == '\r' )
NextCh();
else if( Ch != '\t' ) {
System.
out.
write(Ch
); Location.
Pos++; }
else
do
while( ++Location.Pos % TABSIZE != 0 );
}
static void Reset() {
Ok = true; Message = "Ok";
Location.
Pos = 0; Location.
Line = 1; NextCh();
}
static void Close() {
try {
f.close();
}
}