Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
30
Добавлен:
02.05.2014
Размер:
18 Кб
Скачать
unit LexAuto; {!!! Зависит от входного языка !!!}

interface
{ Модуль, обеспечивающий построение таблицы лексем
  по исходному тексту программы }

uses Classes, TblElem, LexType, LexElem;

{ Функция создания списка лексем по исходному
  тексту программы }
function MakeLexList(listFile: TStrings;
                     listLex: TLexList): integer;

implementation

uses SysUtils, FncTree;

type
{ Перечень всех возможных состояний конечного автомата }
TAutoPos = (
  AP_START,AP_IF1,AP_IF2,AP_NOT1,AP_NOT2,AP_NOT3,
  AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_ELSE4,AP_END2,AP_END3,
  AP_PROG1,AP_PROG2,AP_PROG3,AP_PROG4,AP_OR1,AP_OR2,
  AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,AP_BEGIN5,
  AP_XOR1,AP_XOR2,AP_XOR3,AP_AND1,AP_AND2,AP_AND3,
  AP_WHILE1,AP_WHILE2,AP_WHILE3,AP_WHILE4,AP_WHILE5,
  AP_COMM,AP_COMMSG,AP_ASSIGN,AP_VAR,AP_CONST,
  AP_DO1,AP_DO2,AP_SIGN,AP_LT,AP_FIN,AP_ERR);

function MakeLexList(listFile: TStrings;
                     listLex: TLexList): integer;
{ Функция создания списка лексем по исходному
  тексту программы }
var
  i,j,iCnt,iStr,   { Переменные и счетчики циклов }
  iAll,{ Счетчик общего количества входных символов }
  { Переменные для запоминания позиции начала лексемы }
  iStComm,iStart: integer;
  posCur: TAutoPos;{ Текущее состояние конечного автомата }
  { Строки для временного хранения результатов }
  sCurStr,sTmp: string;
{ Несколько простых процедур для работы со списком лексем }
procedure AddVarToList(posNext: TAutoPos; iP: integer);
{ Процедура добавления переменной в список }
begin
  { Выделяем имя переменной из текущей строки }
  sTmp := System.Copy(sCurStr,iStart,iP-iStart);
  { При создании переменной она сначала заносится
    в таблицу идентификаторов, а потом ссылка на нее -
    в таблицу лексем }
  listLex.Add(TLexem.CreateVar(AddTreeVar(sTmp),
                               iStComm,i,iStart));
  iStart := j;
  iStComm := iAll-1;
  posCur := posNext;
end;
procedure AddVarKeyToList(keyAdd: TLexType;
                          posNext: TAutoPos);
{ Процедура добавления переменной и
  разделителя в список }
begin
  { Выделяем имя переменной из текущей строки }
  sTmp := System.Copy(sCurStr,iStart,j-iStart);
  { При создании переменной она сначала заносится
    в таблицу идентификаторов, а потом ссылка на нее -
    в таблицу лексем }
  listLex.Add(TLexem.CreateVar(AddTreeVar(sTmp),
                               iStComm,i,iStart));
  { Добавляем разделитель после переменной }
  listLex.Add(TLexem.CreateKey(keyAdd,iAll,i,j));
  iStart := j;
  iStComm := iAll-1;
  posCur := posNext;
end;
procedure AddConstToList(posNext: TAutoPos; iP: integer);
{ Процедура добавления константы в список }
begin
  { Выделяем константу из текущей строки }
  sTmp := System.Copy(sCurStr,iStart,iP-iStart);
  { Заносим константу в список вместе с ее значением }
  listLex.Add(TLexem.CreateConst(StrToInt(sTmp),
                                 iStComm,i,iStart));
  iStart := j;
  iStComm := iAll-1;
  posCur := posNext;
end;
procedure AddConstKeyToList(keyAdd: TLexType;
                            posNext: TAutoPos);
{ Процедура добавления константы и разделителя в список }
begin
  { Выделяем константу из текущей строки }
  sTmp := System.Copy(sCurStr,iStart,j-iStart);
  { Заносим константу в список вместе с ее значением }
  listLex.Add(TLexem.CreateConst(StrToInt(sTmp),iStComm,
                                 i,iStart));
  { Добавляем разделитель после константы }
  listLex.Add(TLexem.CreateKey(keyAdd,iAll,i,j));
  iStart := j;
  iStComm := iAll-1;
  posCur := posNext;
end;
procedure AddKeyToList(keyAdd: TLexType;
                       posNext: TAutoPos);
{ Процедура добавления ключевого слова или
  разделителя в список }
begin
  listLex.Add(TLexem.CreateKey(keyAdd,iStComm,i,iStart));
  iStart := j;
  iStComm := iAll-1;
  posCur := posNext;
end;
procedure Add2KeysToList(keyAdd1,keyAdd2: TLexType;
                         posNext: TAutoPos);
{ Процедура добавления ключевого слова и
  разделителя в список }
begin
  listLex.Add(TLexem.CreateKey(keyAdd1,iStComm,i,iStart));
  listLex.Add(TLexem.CreateKey(keyAdd2,iAll,i,j));
  iStart := j;
  iStComm := iAll-1;
  posCur := posNext;
end;
procedure KeyLetter(chNext: char; posNext: TAutoPos);
{ Процедура проверки очередного символа ключевого слова }
begin
  case sCurStr[j] of
    ':': AddVarToList(AP_ASSIGN,j);
    '-': AddVarKeyToList(LEX_SUB,AP_SIGN);
    '+': AddVarKeyToList(LEX_ADD,AP_SIGN);
    '=': AddVarKeyToList(LEX_EQ,AP_SIGN);
    '>': AddKeyToList(LEX_GT,AP_SIGN);
    '<': AddVarToList(AP_LT,j);
    '(': AddVarKeyToList(LEX_OPEN,AP_SIGN);
    ')': AddVarKeyToList(LEX_CLOSE,AP_START);
    ';': AddVarKeyToList(LEX_SEMI,AP_START);
    '{': AddVarToList(AP_COMM,j);
    ' ',#10,#13,#9: AddVarToList(AP_START,j);
    else
      if sCurStr[j] = chNext then posCur := posNext
      else
      if sCurStr[j] in ['0'..'9','A'..'Z','a'..'z','_']
      then posCur := AP_VAR
      else posCur := AP_ERR;
  end{case list};
end;
procedure KeyFinish(keyAdd: TLexType);
{ Процедура проверки завершения ключевого слова }
begin
  case sCurStr[j] of
    '-': Add2KeysToList(keyAdd,LEX_UMIN,AP_SIGN);
    '+': Add2KeysToList(keyAdd,LEX_ADD,AP_SIGN);
    '=': Add2KeysToList(keyAdd,LEX_EQ,AP_SIGN);
    '>': Add2KeysToList(keyAdd,LEX_GT,AP_SIGN);
    '<': AddKeyToList(keyAdd,AP_LT);
    '(': Add2KeysToList(keyAdd,LEX_OPEN,AP_SIGN);
    ')': Add2KeysToList(keyAdd,LEX_CLOSE,AP_START);
    ';': Add2KeysToList(keyAdd,LEX_SEMI,AP_START);
    '0'..'9','A'..'Z','a'..'z','_': posCur := AP_VAR;
    '{': AddKeyToList(keyAdd,AP_COMMSG);
    ' ',#10,#13,#9: AddKeyToList(keyAdd,AP_SIGN);
    else posCur := AP_ERR;
  end{case list};
end;
begin
  { Обнуляем общий счетчик символов и результат функции }
  iAll := 0;
  Result := 0;
  iStComm := 0;
  { Устанавливаем начальное состояние конечного автомата }
  posCur := AP_START;
  { Цикл по всем строкам входного файла }
  iCnt := listFile.Count-1;
  for i:=0 to iCnt do
  begin
    { Позиция начала лексемы - первый символ }
    iStart := 1;
    { Запоминаем текущую строку }
    sCurStr := listFile[i];
    { Цикл по всем символам текущей строки }
    iStr := Length(sCurStr);
    for j:=1 to iStr do
    begin
      { Увеличиваем общий счетчик символов }
      Inc(iAll);
      { Моделируем работу конечного автомата в зависимости
       от состояния КА и текущего символа входной строки }
      case posCur of
        AP_START:
          begin
            { В начальном состоянии запоминаем позицию
              начала лексемы }
            iStart := j;
            iStComm := iAll-1;
            case sCurStr[j] of
              'b': posCur := AP_BEGIN1;
              'i': posCur := AP_IF1;
              'p': posCur := AP_PROG1;
              'e': posCur := AP_ELSE1;
              'w': posCur := AP_WHILE1;
              'd': posCur := AP_DO1;
              'o': posCur := AP_OR1;
              'x': posCur := AP_XOR1;
              'a': posCur := AP_AND1;
              'n': posCur := AP_NOT1;
              ':': posCur := AP_ASSIGN;
              '-': AddKeyToList(LEX_SUB,AP_SIGN);
              '+': AddKeyToList(LEX_ADD,AP_SIGN);
              '=': AddKeyToList(LEX_EQ,AP_SIGN);
              '>': AddKeyToList(LEX_GT,AP_SIGN);
              '<': posCur := AP_LT;
              '(': AddKeyToList(LEX_OPEN,AP_SIGN);
              ')': AddKeyToList(LEX_CLOSE,AP_START);
              ';': AddKeyToList(LEX_SEMI,AP_START);
              '0'..'9': posCur := AP_CONST;
              'A'..'Z','c','f'..'h','j'..'m',
              'q'..'v','y','z','_': posCur := AP_VAR;
              '{': posCur := AP_COMM;
              ' ',#10,#13,#9: ;
              else posCur := AP_ERR;
            end{case list};
          end;
        AP_SIGN:
          begin
            { Состояние, когда может встретиться
              унарный минус }
            iStart := j;
            iStComm := iAll-1;
            case sCurStr[j] of
              'b': posCur := AP_BEGIN1;
              'i': posCur := AP_IF1;
              'p': posCur := AP_PROG1;
              'e': posCur := AP_ELSE1;
              'w': posCur := AP_WHILE1;
              'd': posCur := AP_DO1;
              'o': posCur := AP_OR1;
              'x': posCur := AP_XOR1;
              'a': posCur := AP_AND1;
              'n': posCur := AP_NOT1;
              '-': AddKeyToList(LEX_UMIN,AP_SIGN);
              '(': AddKeyToList(LEX_OPEN,AP_SIGN);
              ')': AddKeyToList(LEX_CLOSE,AP_START);
              '0'..'9': posCur := AP_CONST;
              'A'..'Z','c','f'..'h','j'..'m',
              'q'..'v','y','z','_': posCur := AP_VAR;
              '{': posCur := AP_COMMSG;
              ' ',#10,#13,#9: ;
              else posCur := AP_ERR;
            end{case list};
          end;
        AP_LT:
          { Знак меньше или знак неравенства? }
          case sCurStr[j] of
            'b': AddKeyToList(LEX_LT,AP_BEGIN1);
            'i': AddKeyToList(LEX_LT,AP_IF1);
            'p': AddKeyToList(LEX_LT,AP_PROG1);
            'e': AddKeyToList(LEX_LT,AP_ELSE1);
            'w': AddKeyToList(LEX_LT,AP_WHILE1);
            'd': AddKeyToList(LEX_LT,AP_DO1);
            'o': AddKeyToList(LEX_LT,AP_OR1);
            'x': AddKeyToList(LEX_LT,AP_XOR1);
            'a': AddKeyToList(LEX_LT,AP_AND1);
            'n': AddKeyToList(LEX_LT,AP_NOT1);
            '>': AddKeyToList(LEX_NEQ,AP_SIGN);
            '-': Add2KeysToList(LEX_LT,LEX_UMIN,AP_SIGN);
            '(': Add2KeysToList(LEX_LT,LEX_OPEN,AP_SIGN);
            '0'..'9': AddKeyToList(LEX_LT,AP_CONST);
            'A'..'Z','c','f'..'h','j'..'m','q'..'v',
            'y','z','_': AddKeyToList(LEX_LT,AP_VAR);
            '{': AddKeyToList(LEX_LT,AP_COMMSG);
            ' ',#10,#13,#9: AddKeyToList(LEX_LT,AP_SIGN);
            else posCur := AP_ERR;
          end{case list};
        AP_ELSE1:
          { "else", или же "end", или переменная? }
          case sCurStr[j] of
            'l': posCur := AP_ELSE2;
            'n': posCur := AP_END2;
            ':': AddVarToList(AP_ASSIGN,j);
            '-': AddVarKeyToList(LEX_SUB,AP_SIGN);
            '+': AddVarKeyToList(LEX_ADD,AP_SIGN);
            '=': AddVarKeyToList(LEX_EQ,AP_SIGN);
            '>': AddKeyToList(LEX_GT,AP_SIGN);
            '<': AddVarToList(AP_LT,j);
            '(': AddVarKeyToList(LEX_OPEN,AP_SIGN);
            ')': AddVarKeyToList(LEX_CLOSE,AP_START);
            ';': AddVarKeyToList(LEX_SEMI,AP_START);
            '{': AddVarToList(AP_COMM,j);
            '0'..'9','A'..'Z','a'..'k','m',
            'o'..'z','_': posCur := AP_VAR;
            ' ',#10,#13,#9: AddVarToList(AP_START,j);
            else posCur := AP_ERR;
          end{case list};
        AP_IF1:    KeyLetter('f',AP_IF2);
        AP_IF2:    KeyFinish(LEX_IF);
        AP_ELSE2:  KeyLetter('s',AP_ELSE3);
        AP_ELSE3:  KeyLetter('e',AP_ELSE4);
        AP_ELSE4:  KeyFinish(LEX_ELSE);
        AP_OR1:    KeyLetter('r',AP_OR2);
        AP_OR2:    KeyFinish(LEX_OR);
        AP_DO1:    KeyLetter('o',AP_DO2);
        AP_DO2:    KeyFinish(LEX_DO);
        AP_XOR1:   KeyLetter('o',AP_XOR2);
        AP_XOR2:   KeyLetter('r',AP_XOR3);
        AP_XOR3:   KeyFinish(LEX_XOR);
        AP_AND1:   KeyLetter('n',AP_AND2);
        AP_AND2:   KeyLetter('d',AP_AND3);
        AP_AND3:   KeyFinish(LEX_AND);
        AP_NOT1:   KeyLetter('o',AP_NOT2);
        AP_NOT2:   KeyLetter('t',AP_NOT3);
        AP_NOT3:   KeyFinish(LEX_NOT);
        AP_PROG1:  KeyLetter('r',AP_PROG2);
        AP_PROG2:  KeyLetter('o',AP_PROG3);
        AP_PROG3:  KeyLetter('g',AP_PROG4);
        AP_PROG4:  KeyFinish(LEX_PROG);
        AP_WHILE1: KeyLetter('h',AP_WHILE2);
        AP_WHILE2: KeyLetter('i',AP_WHILE3);
        AP_WHILE3: KeyLetter('l',AP_WHILE4);
        AP_WHILE4: KeyLetter('e',AP_WHILE5);
        AP_WHILE5: KeyFinish(LEX_WHILE);
        AP_BEGIN1: KeyLetter('e',AP_BEGIN2);
        AP_BEGIN2: KeyLetter('g',AP_BEGIN3);
        AP_BEGIN3: KeyLetter('i',AP_BEGIN4);
        AP_BEGIN4: KeyLetter('n',AP_BEGIN5);
        AP_BEGIN5: KeyFinish(LEX_BEGIN);
        AP_END2:   KeyLetter('d',AP_END3);
        AP_END3:
          { "end", или же "end.", или переменная? }
          case sCurStr[j] of
            '-': Add2KeysToList(LEX_END,LEX_UMIN,AP_SIGN);
            '+': Add2KeysToList(LEX_END,LEX_ADD,AP_SIGN);
            '=': Add2KeysToList(LEX_END,LEX_EQ,AP_SIGN);
            '>': Add2KeysToList(LEX_END,LEX_GT,AP_SIGN);
            '<': AddKeyToList(LEX_END,AP_LT);
            '(': Add2KeysToList(LEX_END,LEX_OPEN,AP_SIGN);
            ')':
                Add2KeysToList(LEX_END,LEX_CLOSE,AP_START);
            ';': Add2KeysToList(LEX_END,LEX_SEMI,AP_START);
            '.': AddKeyToList(LEX_FIN,AP_START);
            '0'..'9','A'..'Z','a'..'z','_':
                posCur := AP_VAR;
            '{': AddKeyToList(LEX_END,AP_COMMSG);
            ' ',#10,#13,#9: AddKeyToList(LEX_END,AP_SIGN);
            else posCur := AP_ERR;
          end{case list};
        AP_ASSIGN:
          case sCurStr[j] of
            '=': AddKeyToList(LEX_ASSIGN,AP_SIGN);
            else posCur := AP_ERR;
          end{case list};
        AP_VAR:
          case sCurStr[j] of
            ':': AddVarToList(AP_ASSIGN,j);
            '-': AddVarKeyToList(LEX_SUB,AP_SIGN);
            '+': AddVarKeyToList(LEX_ADD,AP_SIGN);
            '=': AddVarKeyToList(LEX_EQ,AP_SIGN);
            '>': AddVarKeyToList(LEX_GT,AP_SIGN);
            '<': AddVarToList(AP_LT,j);
            '(': AddVarKeyToList(LEX_OPEN,AP_SIGN);
            ')': AddVarKeyToList(LEX_CLOSE,AP_START);
            ';': AddVarKeyToList(LEX_SEMI,AP_START);
            '0'..'9','A'..'Z','a'..'z','_':
               posCur := AP_VAR;
            '{': AddVarToList(AP_COMM,j);
            ' ',#10,#13,#9: AddVarToList(AP_START,j);
            else posCur := AP_ERR;
          end{case list};
        AP_CONST:
          case sCurStr[j] of
            ':': AddConstToList(AP_ASSIGN,j);
            '-': AddConstKeyToList(LEX_SUB,AP_SIGN);
            '+': AddConstKeyToList(LEX_ADD,AP_SIGN);
            '=': AddConstKeyToList(LEX_EQ,AP_SIGN);
            '>': AddConstKeyToList(LEX_GT,AP_SIGN);
            '<': AddConstToList(AP_LT,j);
            '(': AddConstKeyToList(LEX_OPEN,AP_SIGN);
            ')': AddConstKeyToList(LEX_CLOSE,AP_START);
            ';': AddConstKeyToList(LEX_SEMI,AP_START);
            '0'..'9': posCur := AP_CONST;
            '{': AddConstToList(AP_COMM,j);
            ' ',#10,#13,#9: AddConstToList(AP_START,j);
            else posCur := AP_ERR;
          end{case list};
        AP_COMM:
          case sCurStr[j] of
            '}': posCur := AP_START;
          end{case list};
        AP_COMMSG:
          case sCurStr[j] of
            '}': posCur := AP_SIGN;
          end{case list};
      end{case pos};
      { Проверяем, не достигнут ли конец строки }
      if j = iStr then
      begin
        { Конец строки - это конец текущей лексемы }
        case posCur of
          AP_IF2:    AddKeyToList(LEX_IF,AP_SIGN);
          AP_PROG4:  AddKeyToList(LEX_PROG,AP_START);
          AP_ELSE4:  AddKeyToList(LEX_ELSE,AP_START);
          AP_BEGIN5: AddKeyToList(LEX_BEGIN,AP_START);
          AP_WHILE5: AddKeyToList(LEX_WHILE,AP_SIGN);
          AP_END3:   AddKeyToList(LEX_END,AP_START);
          AP_OR2:    AddKeyToList(LEX_OR,AP_SIGN);
          AP_DO2:    AddKeyToList(LEX_DO,AP_SIGN);
          AP_XOR3:   AddKeyToList(LEX_XOR,AP_SIGN);
          AP_AND3:   AddKeyToList(LEX_AND,AP_SIGN);
          AP_NOT3:   AddKeyToList(LEX_AND,AP_SIGN);
          AP_LT:     AddKeyToList(LEX_LT,AP_SIGN);
          AP_FIN:    AddKeyToList(LEX_FIN,AP_START);
          AP_CONST:  AddConstToList(AP_START,j+1);
          AP_ASSIGN: posCur := AP_ERR;
          AP_IF1,AP_PROG1,AP_PROG2,AP_PROG3,
          AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_XOR1,AP_XOR2,
          AP_OR1,AP_DO1,AP_AND1,AP_AND2,AP_NOT1,AP_NOT2,
          AP_WHILE1,AP_WHILE2,AP_WHILE3,AP_WHILE4,
          AP_END2,AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,
          AP_VAR: AddVarToList(AP_START,j+1);
        end{case pos2};
      end;
      { Проверяем не была ли ошибка в лексемах }
      if posCur = AP_ERR then
      begin
        { Если была ошибка, вычисляем позицию
          ошибочной лексемы }
        iStart := (j - iStart)+1;
        { и запоминаем ее в виде фиктивной лексемы в начале
          списка для детальной диагностики ошибки }
        listLex.Insert(0,
          TLexem.CreateInfo('Недопустимая лексема',
                            iAll-iStart,i,iStart));
        { Если ошибка, прерываем цикл }
        Break;
      end;
    end{for j};
    { В конце строки увеличиваем общий счетчик символов
      на 2: конец строки и возврат каретки }
    Inc(iAll,2);
    { Если ошибка, запоминаем номер ошибочной строки
      и прерываем цикл }
    if posCur = AP_ERR then
    begin
      Result := i+1;
      Break;
    end;
  end{for i};
  { Если комментарий не был закрыт, то это ошибка }
  if posCur in [AP_COMM,AP_COMMSG] then
  begin
    listLex.Insert(0,
      TLexem.CreateInfo('Незакрытый комментарий',
                        iStComm,iCnt,iAll-iStComm));
    Result := iCnt;
  end
  else
  if not (posCur in [AP_START,AP_SIGN,AP_ERR]) then
  { Если КА не в начальном состоянии -
    это неверная лексема }
  begin
    listLex.Insert(0,
      TLexem.CreateInfo('Незавершенная лексема',
                        iAll-iStart,iCnt,iStart));
    Result := iCnt;
  end;
end;

end.
Соседние файлы в папке Cursov