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