Skip to content
Marcus Fernstrom edited this page Jun 27, 2019 · 2 revisions

yywrap

yywrap is used to signal that the lexer should restart scanning the input.

Practically you use it for lexing multiple files.

Here's a complete lexer program which will count characters, words, and lines from any number of files from the commandline.

We're using yywrap to see if we're done or reset if needed.

%{
  {
    Plex-only wordcount, multiple file arguments
  }
  program wordcounter;

  {$mode objfpc}

  uses sysutils, yacclib, lexlib;

  var
    charCount, wordCount, lineCount, currentFile: Integer;
    srcFile: TextFile;

  procedure resetStatus;
  begin
    charCount := 0;
    wordCount := 0;
    lineCount := 0;
  end;

  function yywrap():Boolean;
  begin
    // Output summary for current file
    writeln(format('%d characters     %d words     %d lines     %s', [charCount, wordCount, lineCount, paramStr(currentFile)]));
  
    // If there's more than one file, reset and go again
    if currentFile < paramCount then begin
      resetStatus;
      
      // Update currentFile to keep track of argument file position
      inc(currentFile);
      
      // Close the current file
      close(srcFile);
      
      // Assign next file and reset to place the cursor at the beginning
      assign(srcFile, paramStr(currentFile));
      reset(srcFile);

      // Signal that we're not finished
      result := false;
    end else
      // There were no more files so it's true that we're done
      result := true;
  end;
%}

word [^ \t\n]+
eol \n

%%

{word}      begin inc(wordCount); charCount := charCount + yyleng; end;
{eol}       begin inc(charCount); inc(lineCount); end;
.           begin inc(charCount); end;
%%

begin
  // Set starting counts
  resetStatus;
  currentFile := 1;

  // Assign and reset the first file
  assign(srcFile, ParamStr(1));
  reset(srcFile);

  // Set lexer input to be the file
  yyinput := srcFile;

  // Lex
  yylex();

  // Close the current file
  close(srcFile);
end.

To try it we use plex filename.l to generate the fpc source file, and then fpc filename.pas to compile it.

Run it with ./filename <file to scan> <second file to scan>

When the program runs we first set all status values to 0 by calling the procedure resetStatus, then we set the currentFile to 1 to correspond with the first passed in parameter value.

Now we assign the first file to srcFile and set the lexers yyinput to srcFile to use it as our input.

Finally we call the lexing function yylex();

When the lexer has completed lexing the file, it calls yywrap.

In yywrap we check if currentFile is the same as paramCount and if there are, we close the current file, set srcFile to the next file, and returns false to signal that yylex(); needs to run again.

If we ARE are the last value, we just return true, close the srcFile, and the program exits.

Clone this wiki locally