Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LexAndYaccCalculator example #161

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions tests/LexAndYaccCalculator/LexAndYaccCalculator.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>lexandyacccalculator_example</RootNamespace>
</PropertyGroup>

<ItemGroup>
<Compile Include="Syntax.fs" />
<FsYacc Include="Parser.fsy">
<OtherFlags>--module Parser</OtherFlags>
</FsYacc>
<FsLex Include="Lexer.fsl">
<OtherFlags>--module Lexer --unicode</OtherFlags>
</FsLex>
<Compile Include="Parser.fsi" />
<Compile Include="Parser.fs" />
<Compile Include="Lexer.fs" />
<Compile Include="Program.fs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="FsLexYacc" Version="10.2.0" />
</ItemGroup>

</Project>
Expand Down
48 changes: 48 additions & 0 deletions tests/LexAndYaccCalculator/Lexer.fsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{

open FSharp.Text.Lexing
open Parser

type Lexbuf = LexBuffer<char>

let lexeme (lexbuf : Lexbuf) = Lexbuf.LexemeString lexbuf

let newline (lexbuf: LexBuffer<_>) =
lexbuf.StartPos <- lexbuf.StartPos.NextLine

}

// Regular expressions
let whitespace = [' ' '\t' ]
let newline = ('\n' | '\r' '\n')
let separator = '_'
let letter = '\Lu' | '\Ll' | '\Lt' | '\Lm' | '\Lo' | '\Nl'
let digit = '\Nd'
let anystring = anychar*
let integer = digit ((digit | separator)* digit)?
let char = '\'' ( [^'\\''\n''\r''\t''\b'] | escape_char) '\''

let ident_char =
letter
| digit
| '_'
let ident = letter ident_char*

let anychar = [^'\n''\r']

let comment = "/*" anystring "*/"

rule tokenstream = parse
| whitespace { tokenstream lexbuf }
| newline { newline lexbuf; tokenstream lexbuf }
// Identifiers
| ident { ID(lexeme lexbuf) }
| integer { INT(int (lexeme lexbuf)) }
// Operators
| "+" { OP_PLUS }
| "-" { OP_MINUS }
| "*" { OP_TIMES }
| "/" { OP_DIVIDE }
// --------------------------
| _ { failwith ("ParseError" + LexBuffer<_>.LexemeString lexbuf) }
| eof { Parser.EOF }
40 changes: 40 additions & 0 deletions tests/LexAndYaccCalculator/Parser.fsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Signature file for parser generated by fsyacc
module Parser
type token =
| OP_PLUS
| OP_MINUS
| OP_TIMES
| OP_DIVIDE
| LPAREN
| RPAREN
| EOF
| INT of (int)
| ID of (string)
type tokenId =
| TOKEN_OP_PLUS
| TOKEN_OP_MINUS
| TOKEN_OP_TIMES
| TOKEN_OP_DIVIDE
| TOKEN_LPAREN
| TOKEN_RPAREN
| TOKEN_EOF
| TOKEN_INT
| TOKEN_ID
| TOKEN_end_of_input
| TOKEN_error
type nonTerminalId =
| NONTERM__startstart
| NONTERM_start
| NONTERM_Expr
/// This function maps tokens to integer indexes
val tagOfToken: token -> int

/// This function maps integer indexes to symbolic token ids
val tokenTagToTokenId: int -> tokenId

/// This function maps production indexes returned in syntax errors to strings representing the non terminal that would be produced by that production
val prodIdxToNonTerminal: int -> nonTerminalId

/// This function gets the name of a token as a string
val token_to_string: token -> string
val start : (FSharp.Text.Lexing.LexBuffer<'cty> -> token) -> FSharp.Text.Lexing.LexBuffer<'cty> -> ( Syntax.Expr )
27 changes: 27 additions & 0 deletions tests/LexAndYaccCalculator/Parser.fsy
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
%{
open Syntax
%}

%start start
%token <string> ID
%token <int> INT

%token LPAREN RPAREN EOF

%token OP_PLUS OP_MINUS OP_TIMES OP_DIVIDE

%left OP_PLUS OP_MINUS
%left OP_TIMES OP_DIVIDE
%type < Syntax.Expr > start


%%

start: Expr { $1 }

Expr: ID { Var($1) }
Comment on lines +15 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove start and use Expr as the starting symbol?

Suggested change
%type < Syntax.Expr > start
%%
start: Expr { $1 }
Expr: ID { Var($1) }
%type < Syntax.Expr > Expr
%%
Expr: ID { Var($1) }

| INT { Int($1) }
| Expr OP_PLUS Expr { Add($1,$3) }
| Expr OP_MINUS Expr { Sub($1,$3) }
| Expr OP_TIMES Expr { Mul($1,$3) }
| Expr OP_DIVIDE Expr { Div($1,$3) }
20 changes: 20 additions & 0 deletions tests/LexAndYaccCalculator/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
open System.IO
open FSharp.Text.Lexing
open Syntax

let testLexerAndParserFromString text expected =
let lexbuf = LexBuffer<char>.FromString text

let parse = Parser.start Lexer.tokenstream lexbuf

printfn "parse: result = %A, expected %A" parse expected

testLexerAndParserFromString "1" (Int 1)
testLexerAndParserFromString "hello" (Var "hello")
testLexerAndParserFromString "1 + 1" (Add((Int 1),(Int 1)))
testLexerAndParserFromString "1 - 1" (Sub((Int 1),(Int 1)))
testLexerAndParserFromString "1 * 1" (Mul((Int 1),(Int 1)))
testLexerAndParserFromString "1 / 1" (Div((Int 1),(Int 1)))
testLexerAndParserFromString "1 + 2 + 3" (Add(Add(Int 1, Int 2), Int 3))
testLexerAndParserFromString "1 + 2 * 3" (Add(Int 1, Mul(Int 2, Int 3)))
testLexerAndParserFromString "1 * 2 + 3" (Add(Mul(Int 1, Int 2), Int 3))
11 changes: 11 additions & 0 deletions tests/LexAndYaccCalculator/Syntax.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Syntax

type Id = Id of string

type Expr =
| Var of string
| Int of int
| Add of Expr * Expr
| Sub of Expr * Expr
| Mul of Expr * Expr
| Div of Expr * Expr