program LexicalAnalysis;

{$mode objfpc}{$H+}

uses
  SysUtils;

var
  Lines: array of string;
  Row, Col: Integer;
  ErrorFound: Boolean;


procedure ShowError;
begin
  Writeln('ERROR: invalid word at line ',
          Row, ', position ', Col);
  ErrorFound := True;
end;


function CheckFirstWord(var S: string; var P: Integer): Boolean;
var
  StartPos: Integer;
begin
  Result := False;
  StartPos := P;

  { (000)* }

  while (P + 2 <= Length(S)) and
        (S[P] = '0') and
        (S[P + 1] = '0') and
        (S[P + 2] = '0') do
  begin
    P := P + 3;
  end;

  { 001 }

  if (P + 2 > Length(S)) or
     (S[P] <> '0') or
     (S[P + 1] <> '0') or
     (S[P + 2] <> '1') then
  begin
    P := StartPos;
    Exit;
  end;

  P := P + 3;

  { (010)* }

  while (P + 2 <= Length(S)) and
        (S[P] = '0') and
        (S[P + 1] = '1') and
        (S[P + 2] = '0') do
  begin
    P := P + 3;
  end;

  Result := True;
end;


function CheckSecondWord(var S: string; var P: Integer): Boolean;
begin
  Result := False;

  { First two symbols must be ab }

  if (P + 1 > Length(S)) or
     (S[P] <> 'a') or
     (S[P + 1] <> 'b') then
    Exit;

  P := P + 2;

  { After ab: a,b,c,d }

  while (P <= Length(S)) and
        (S[P] in ['a', 'b', 'c', 'd']) do
  begin
    P := P + 1;
  end;

  Result := True;
end;


procedure SkipComment(var S: string; var P: Integer);
begin
  { Skip apostrophe }

  P := P + 1;

  { Skip comment to end of line }

  while P <= Length(S) do
    P := P + 1;
end;


procedure AnalyzeLine(var S: string; LineNumber: Integer);
var
  P: Integer;
  OldP: Integer;
  TokenFound: Boolean;
begin
  P := 1;

  while P <= Length(S) do
  begin

    { Skip spaces }

    while (P <= Length(S)) and
          (S[P] = ' ') do
      P := P + 1;

    if P > Length(S) then
      Break;


    { Comment }

    if S[P] = '''' then
    begin
      SkipComment(S, P);
      Break;
    end;


    OldP := P;
    TokenFound := False;


    { First word }

    if S[P] = '0' then
    begin
      if CheckFirstWord(S, P) then
        TokenFound := True;
    end


    { Second word }

    else if S[P] = 'a' then
    begin
      if CheckSecondWord(S, P) then
        TokenFound := True;
    end;


    { Invalid word }

    if not TokenFound then
    begin
      Row := LineNumber;
      Col := OldP;
      ShowError;
      Exit;
    end;


    { Check separator }

    if (P <= Length(S)) and
       not (S[P] in [' ', '''']) then
    begin
      Row := LineNumber;
      Col := P;
      ShowError;
      Exit;
    end;

  end;
end;


var
  N, I: Integer;

begin

  Writeln('==============================================');
  Writeln('           LEXICAL ANALYZER');
  Writeln('                 VARIANT 34');
  Writeln('==============================================');
  Writeln;

  Writeln('WORD 1: (000)*001(010)*');
  Writeln('WORD 2: ab(a|b|c|d)*');
  Writeln('COMMENT: apostrophe to end of line');
  Writeln;


  Write('Enter number of lines: ');
  ReadLn(N);

  SetLength(Lines, N);

  Writeln;
  Writeln('Enter text:');

  for I := 1 to N do
    ReadLn(Lines[I - 1]);


  ErrorFound := False;


  for I := 1 to N do
  begin
    AnalyzeLine(Lines[I - 1], I);

    if ErrorFound then
      Break;
  end;


  Writeln;

  if not ErrorFound then
    Writeln('No errors found.');


  Writeln;
  Writeln('Press Enter to exit.');
  ReadLn;

end.