I've downloaded BYACC and rewrote parts of routines/added some routines to BYACC so BYACC produces FreeBASIC syntax.
BYACC or Berkeley YACC is a public domain implementation of
AT&T YACC. YACC is a compiler compiler that, given an input
grammar + semantic actions, builds a LALR parser coded in C code.
It does not build a lexer (the programmer must supply one).
You can find a YACC manual here
http://dinosaur.compilertools.net/yacc/index.html
Extent of rewrite
No attempt has been made to rewrite the entire BYACC source code. Only
the parts that have to do with the output of C code have been rewritten.
The files that have (partly) been rewritten are:
- output.c;
- reader.c;
- skeleton.c
When running yacc the content of skeleton.c is combined with
the user code yielding source code that can be compiled using the
FreeBASIC compiler. For further details see YACC manual.
INSTALLATION
Provided are the YACC/FB source, a WIN32 binary and a copy of the
YACC manual.
A package containing the above can be downloaded from
http://www.sarmardar.nl/FreeBASIC/byacc_fb_02.zip
DIFFERENCES BETWEEN BYACC AND BYACC/FB
There are a some things you need to keep in mind when working with BYACC/FB.
- semantic actions
Code MUST be enclosed by { }. In some versions of YACC the use of
{ and } is not mandatory but BYACC/FB expects { at the start of
a semantic action and } at the end of a semantic action.
- comments
Comments within the FreeBASIC - only parts of the input file can contain
FreeBASIC style comments. In the parts of the input file that are
processed by YACC use of C style comments is
mandatory (example: /* some_comment */).
This means you can use FB style comments
- within semantic actions;
- within the %{ ... %} block;
- within the block after the final %%.
- command line options
The option -r does not produce usable code. The option has not been dropped (yet) from the YACC executable but running BYACC/FB with the option -r will produce non - usable output.
FINAL REMARKS
The shared variables found in BYACC\FB have been copied from the orginal C code. Why BYACC uses so many shared variables is unclear. More 'modern' implementations of LALR parsers (LEMON/BISON/others) tend to use less shared variables (if any). I'm hoping to rewrite BYACC\FB so it will not rely as much on Shared variables as it does now.
This is the very first release of BYACC/FB so you may expect bugs
in either BYACC/FB or the code it produces.
Below you find an example of an input file (a simple expression grammar). It expects it's input to be in "inin.txt" (this is hard coded).
Possible content of inin.txt (last line must have a newline at the end):
8 & 8 | 9 * 55
8 * ((7 & 2))
5 + 4 * 6 / 8
8 * 6 + 1
If the example is saved as expression.y then the following command line will yield a file called expression.bas (due to the -v option a description of the states produced will be written to y.output).
fbyacc -o expression.bas -v expression.y
Now you can run the fb compiler like so
fbc expression.bas
which will produce an expression parser (it will expect input to be in inin.txt).
Code: Select all
%{
#include "crt/stdio.bi"
#include "crt/ctype.bi"
#include "crt/time.bi"
Dim Shared regs(0 To 26) As Integer
Dim Shared base As Integer
%}
%start list
%token DIGIT
%token LETTER
%left "|"
%left "&"
%left "+" "-"
%left "*" "/" "%"
%left UMINUS /* supplies precedence for unary minus */
%% /* beginning of rules section */
list : /* empty */
| list stat "\n"
| list error "\n"
{ yyerrok }
;
stat : expr
{ Print Using "#####";$1}
| LETTER "=" expr
{ regs($1) = $3 }
;
expr : "(" expr ")"
{ $$ = $2 }
| expr "+" expr
{ $$ = $1 + $3 }
| expr "-" expr
{ $$ = $1 - $3 }
| expr "*" expr
{ $$ = $1 * $3 }
| expr "/" expr
{ $$ = $1 / $3 }
| expr "%" expr
{ $$ = $1 Mod $3 }
| expr "&" expr
{ $$ = $1 And $3 }
| expr "|" expr
{ $$ = $1 Or $3 }
| "-" expr %prec UMINUS
{ $$ = - $2 }
| LETTER
{ $$ = regs($1) }
| number
;
number: DIGIT
{ $$ = $1
If ($1 = 0) Then
base = 8
Else
base = 10
End If
/' comment '/
}
| number DIGIT
{ $$ = base * $1 + $2 }
;
%% /' start of programs '/
Dim Shared in_hndl As Integer
Sub main ()
in_hndl = FreeFile()
Open "inin.txt" For Input As #in_hndl
Var t1 = clock()
Do Until(EOF(in_hndl))
yyparse()
Loop
Var t2 = clock()
Print Using "Start = ###########";t1
Print Using "End = ###########";t2
Close #in_hndl
End Sub
Sub yyerror_(ByVal s As ZString Ptr)
Print *s
End Sub
#define ULA 97 'Asc("a")
#define ULZ 122 'Asc("z")
#define UD0 48 'Asc("0")
#define UD9 57 'Asc("9")
#define USPC 32 'Asc(" ")
Function yylex() As Integer
/' lexical analysis routine '/
/' returns LETTER for a lower case letter, yylval = 0 through 25 '/
/' return DIGIT for a digit, yylval = 0 through 9 '/
/' all other characters are returned immediately '/
Dim c As UByte
Get #in_hndl,,c
While (c = USPC)
Get #in_hndl,,c
Wend
'C is not whitespace
Select Case As Const(c)
Case ULA To ULZ
yylval = c - ULA
Return LETTER
Case UD0 To UD9
yylval = c - UD0
Return DIGIT
End Select
Return(c)
End Function
main()