Difference between revisions of "Plex and Pyacc"

From Lazarus wiki
(Simple example application)
m (Text replace - "delphi>" to "syntaxhighlight>")
Line 21: Line 21:
 
===build.sh===
 
===build.sh===
  
<delphi>
+
<syntaxhighlight>
 
plex lexer.l
 
plex lexer.l
 
pyacc -d parser.y
 
pyacc -d parser.y
 
mv parser.pas calculadora.pas
 
mv parser.pas calculadora.pas
 
fpc calculadora.pas
 
fpc calculadora.pas
</delphi>
+
</syntaxhighlight>
  
 
===lexer.l===
 
===lexer.l===
  
<delphi>
+
<syntaxhighlight>
 
{ Analisador léxico da calculadora para a disciplina de PCS
 
{ Analisador léxico da calculadora para a disciplina de PCS
  
Line 62: Line 62:
 
   Result := 1;
 
   Result := 1;
 
end;
 
end;
</delphi>
+
</syntaxhighlight>
  
 
===parser.y===
 
===parser.y===
  
<delphi>
+
<syntaxhighlight>
 
/* Parser
 
/* Parser
  
Line 126: Line 126:
 
   yyparse ();
 
   yyparse ();
 
end.
 
end.
</delphi>
+
</syntaxhighlight>
  
 
===How to use it===
 
===How to use it===

Revision as of 15:51, 24 March 2012

Free Pascal comes with substitutes for the GNU projects Lex and YACC. They are called Plex and Pyacc and they can be used to generate compilers and regular expression analyzers in Pascal instead of C.

Library contents

TP Lex and Yacc can be found here: http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/utils/tply/

Documentation

Download the manual here: http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/utils/tply/tply.doc?revision=1

Simple example application

This is a very simple calculator, which shows how to use plex and pyacc. The files in this simple project are:

  • build.sh
  • lexer.l
  • parser.y

WARNING: The code bellow compiles but currently doesn't work

build.sh

plex lexer.l
pyacc -d parser.y
mv parser.pas calculadora.pas
fpc calculadora.pas

lexer.l

{ Analisador léxico da calculadora para a disciplina de PCS

   Aluno: Felipe Monteiro de Carvalho                           }

%{
%}
%%

[0-9]+[dD]?          begin yylval.yyInteger := StrToInt(yytext); yyruleno := NUMBER; end;

[0-9a-fA-F]+[hH]     begin yylval.yyInteger := StrToInt(yytext); yyruleno := NUMBER; end;

[ \t]                begin end; { ignorar espaços em branco }

[-]                  begin yyruleno := MENOS; end;

[+*/()]              begin yyruleno := Integer(yytext[0]); end;

[=][hH]              begin yyruleno := IGUALH; end;

[=][dD]?             begin yyruleno := IGUALD; end;

\n                   begin yyruleno := Integer(yytext[0]); end;

.                    begin yyerror('Caracter inexperado'); end;

%%
function meuyywrap (): Integer;
begin
  Result := 1;
end;

parser.y

/* Parser

   Aluno: Felipe Monteiro de Carvalho                           */
%{
program calculadora;

{$mode delphi}

uses SysUtils, yacclib, lexlib;

%}

%start entrada
%token <Integer> NUMBER IGUALD IGUALH MENOS
%type <Integer> expressao termo fator

%%

entrada
    : /* linha vazia */     {  }
    | entrada linha         {  }
    ;
linha
    : expressao IGUALD '\n' { WriteLn(Format('Resultado: %d', [$1])); }
    | expressao IGUALH '\n' { WriteLn(Format('Resultado: %H', [$1])); }
    ;
expressao
    : expressao '+' termo   { $$ := $1 + $3; }
    | expressao MENOS termo { $$ := $1 - $3; }
    | termo                 { $$ := $1; }
    ;
termo
    : termo '*' fator       { $$ := $1 * $3; }
    | termo '/' fator       { if ($3 = 0) then
                                 yyerror('Divisao por zero!')
                              else
                                 $$ := $1 div $3; }
    | fator                 { $$ := $1; }
    ;
fator
    : NUMBER                { $$ := $1; }
    | MENOS NUMBER          { $$ := -1 * $2; }
    | '(' expressao ')'     { $$ := $2; }
    ;

%%

procedure meuyyerror(s: PChar);  // Called by yyparse on error
begin
  WriteLn(Format('Erro: %s', [s]));
end;

{$include lexer.pas}

begin
  yywrap := @meuyywrap;
//  yyerror := @meuyyerror;
  yyparse ();
end.

How to use it

Type for example: 5+3=

And it will answer with: 8

You can also try 3*8=H to request an answer in Hexadecimal instead of decimal