Разработка языка, предназначенного для программирования потоковых вычислений, страница 7


Поиск в таблицах идентификаторов/констант и пополнение таблиц. Формирование лексем.

Для хранения идентификаторов, констант и предопределённых слов языка используются хэш-таблицы идентификаторов, констант и предопределённых слов языка соответственно. Для каждого блока типа vars или do создаётся своя хэш-таблица идентификаторов, которая заносится в общую хэш-таблицу идентификаторов, в которой ключами являются имена блоков.

//временная таблица идентификатор одного блока

final Hashtable identHash = new Hashtable();

//таблица идентификаторов всех блоков

final Hashtable identTableBlock = new Hashtable();

//таблица констант

final Hashtable constHash = new Hashtable();

//таблица предопределенных слов языка

final Hashtable defHash = new Hashtable();

Таблицы имеют рандомизированную организацию. Занесение идентификаторов и констант в соответствующие таблицы производится с помощью действий включённых в систему регулярных выражений.

Для целых констант:

if(my.GTNB() == false){if(constHash.get(Lexem.textOfWord.toString()) == null)

{Lexem.wordIndex = constCnt++; constHash.put(Lexem.textOfWord.toString(),Lexem);}}

Для вещественных констант:

if(constHash.get(Lexem.textOfWord.toString()) == null)

{Lexem.wordIndex = constCnt++; constHash.put(Lexem.textOfWord.toString(),Lexem);}

Для идентификаторов:

if(my.GTNB() == false){if(identHash.get(Lexem.textOfWord.toString()) == null && defHash.get(Lexem.textOfWord.toString()) == null)

{Lexem.wordIndex = my.GetCnt(); my.IncCnt(); identHash.put(Lexem.textOfWord.toString(),Lexem);}}

По завершению проверки очередного блока, созданная для него таблица идентификаторов по ключу-имени блока заносится в общую таблицу идентификаторов:

identTableBlock.put(NameBlock.get(NameBlock.size()-1),identHash.clone());identHash.clear();

В классе лексического анализатора определён счётчик констант:

//счетчик констант

int constCnt = 0;

Счётчик идентификаторов определён в моём классе, так как он используется как лексическим, так и синтаксическим анализаторами. В этом же классе определены два флага. Один из них используется для не занесения имен блоков и данных из блоков связей в таблицы идентификаторов. Класс приведён ниже:

//мой класс

class MyClass{

 private boolean ThisNameBlock;

 private boolean ThisOnlyIdent;

 private int identCnt;

public MyClass()

 {

//флаг для не занесения имени блока к таблицу идентификаторов и констант

  ThisNameBlock = false;

//флаг для определения, имеется в операторе присваивания единичный идентификатор или выражение(используется для проверке недопустимости присваивания переменной самой себе)

  ThisOnlyIdent = true;

//счетчик идентификаторов

  identCnt=0;

 }

public void TNBT(){  ThisNameBlock=true; }

public void TNBF(){  ThisNameBlock=false; }

public boolean GTNB () { return ThisNameBlock; }

public void TOIT(){  ThisOnlyIdent=true; }

public void TOIF(){  ThisOnlyIdent=false; }

public boolean GTOI () { return ThisOnlyIdent; }

public void IncCnt(){  identCnt=identCnt+1; }

public int GetCnt () { return identCnt; }

}

Формирование таблицы предопределённых слов происходит на этапе восстановления дерева грамматического разбора. В функцию parse для этого вносится следующее:

// занесение предопределенных слов в таблицу предопределенных слов

int i=0;

for(; i<words.length; i++)

defHash.put(words[i], new Integer(i));

Ключом для помещение новых значений в таблицы является текстовое представление идентификаторов, констант и предопределённых слов. По ключу в таблицы помещаются порядковые номера новых элементов таблиц. Порядковый номер соответствует индексу данного слова в группе идентификаторов, констант или предопределённых слов. Ключ и индекс слова в группе и образуют лексему.

Так как идентификаторы являются переменными, то в дальнейшем с каждым идентификатором придется связать его значение. Для этого используется таблица значений ResultHash, в которую заносятся значения переменных по индексу слова в группе.