Skip to content

Commit c884ca2

Browse files
committed
simple basic parser
1 parent 50372f8 commit c884ca2

File tree

8 files changed

+226
-0
lines changed

8 files changed

+226
-0
lines changed

Parsers.sln

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Parsers", "Parsers\Parsers.fsproj", "{7068A710-F067-4654-876A-53D8CCB52451}"
4+
EndProject
5+
Global
6+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7+
Debug|Any CPU = Debug|Any CPU
8+
Release|Any CPU = Release|Any CPU
9+
EndGlobalSection
10+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
11+
{7068A710-F067-4654-876A-53D8CCB52451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12+
{7068A710-F067-4654-876A-53D8CCB52451}.Debug|Any CPU.Build.0 = Debug|Any CPU
13+
{7068A710-F067-4654-876A-53D8CCB52451}.Release|Any CPU.ActiveCfg = Release|Any CPU
14+
{7068A710-F067-4654-876A-53D8CCB52451}.Release|Any CPU.Build.0 = Release|Any CPU
15+
EndGlobalSection
16+
EndGlobal

Parsers/AST.fs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module Parsers.AST
2+
3+
type sourceExpr =
4+
| Number of int
5+
| Mult of list<sourceExpr>
6+
| Add of list<sourceExpr>
7+
| Var of string
8+
9+
type sourceAst =
10+
| Asgn of string*sourceExpr
11+
| Print of sourceExpr
12+
13+
type targetExpr =
14+
| TNumber of int
15+
| TAdd of list<targetExpr>
16+
| TVar of string
17+
18+
type targetAst =
19+
| TStmt of string*targetExpr

Parsers/Combinators.fs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
module Parsers.Combinators
2+
3+
type Parser<'result> = list<char> -> Option<list<char>*'result>
4+
5+
let satisfy predicate: Parser<char> =
6+
fun input ->
7+
match input with
8+
| hd::tl when predicate hd -> Some(tl, hd)
9+
| _ -> None
10+
11+
let p_char ch: Parser<char> =
12+
satisfy (fun x -> ch = x)
13+
14+
let p_epsilon:Parser<unit> = fun input -> Some(input,())
15+
16+
let p_seq (p1: Parser<'r1>) (p2:'r1 -> Parser<'r2>): Parser<'r2> =
17+
fun input ->
18+
match p1 input with
19+
| None -> None
20+
| Some (rest, result) -> p2 result rest
21+
22+
let p_alt (p1:Parser<'r>) (p2:Parser<'r>): Parser<'r> =
23+
fun input ->
24+
match p1 input with
25+
| None -> p2 input
26+
| x -> x
27+
28+
let fmap (f:'r1 -> 'r2) (p:Parser<'r1>): Parser<'r2> =
29+
fun input ->
30+
match p input with
31+
| None -> None
32+
| Some(rest, res) -> Some(rest, f res)
33+
34+
let rec p_many (p:Parser<'r>): Parser<list<'r>> =
35+
p_alt (p_seq p (fun res -> fmap (fun tl -> res::tl) (p_many p)))
36+
(fmap (fun _ -> []) p_epsilon)
37+
38+
let p_some (p:Parser<'r>): Parser<list<'r>> =
39+
p_seq p (fun res -> fmap (fun tl -> res::tl) (p_many p))
40+
41+
let p_list (p_elem:Parser<'elem>) (p_sep:Parser<unit>) =
42+
p_seq p_elem (fun res -> fmap (fun tl -> res :: tl)
43+
(p_many (p_seq p_sep (fun _ -> p_elem))))
44+
45+
let p_ignore p = fmap (fun _ -> ()) p
46+
47+
let p_kw (kw:string): Parser<string> =
48+
let chars = kw.ToCharArray()
49+
Array.fold
50+
(fun parser curChar ->
51+
p_seq parser (fun res -> fmap (fun char -> char::res) (p_char curChar)))
52+
(fmap (fun _ -> []) p_epsilon)
53+
chars
54+
|> fmap (fun charList -> charList |> List.rev |> Array.ofList |> System.String)
55+
56+
57+
let run =
58+
fun (p: Parser<'r>) (input: string) ->
59+
p (List.ofArray <| input.ToCharArray())

Parsers/ExprParser.fs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module Parsers.ExprParser
2+
3+
open Parsers.Combinators
4+
open Parsers.AST
5+
6+
let p_ident: Parser<string> =
7+
p_some (satisfy (fun x -> List.contains x ['a'..'z']))
8+
|> fmap (fun res -> res |> Array.ofList |> System.String)
9+
10+
let p_num =
11+
p_seq (satisfy (fun x -> List.contains x ['1'..'9']))
12+
(fun res -> fmap (fun tl -> res :: tl) (p_many (satisfy (fun x -> List.contains x ['0'..'9']))))
13+
|> fmap (fun res -> res |> Array.ofList |> System.String |> int |> Number)
14+
15+
let p_mult =
16+
p_list (p_alt p_num (fmap Var p_ident)) (p_ignore (p_char '*'))
17+
|> fmap Mult
18+
19+
let p_add =
20+
p_list p_mult (p_ignore (p_char '+'))
21+
|> fmap Add
22+
23+
let p_asgn = p_seq p_ident
24+
(fun ident_name -> p_seq (p_ignore (p_char '='))
25+
(fun _ -> fmap (fun expr -> Asgn (ident_name, expr)) p_add))
26+
27+
28+
let p_kw_print = p_kw "print"
29+
30+
let p_print = p_seq p_kw_print (fun _ -> p_seq (p_char ':') (fun res -> fmap Print p_add))
31+
32+
let p_prog = p_list (p_alt p_print p_asgn) (p_ignore (p_char '\n'))

Parsers/Interpreter.fs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module Parsers.Interpreter
2+
3+
open System.Collections.Generic
4+
open Parsers.AST
5+
6+
let rec eval (context:Dictionary<_,_>) expr =
7+
match expr with
8+
| Number n -> n
9+
| Mult l -> l |> List.map (eval context) |> List.reduce (*)
10+
| Add l -> l |> List.map (eval context) |> List.reduce (+)
11+
| Var v_name ->
12+
if context.ContainsKey v_name
13+
then context[v_name]
14+
else failwithf $"Var with name {v_name} not declared."
15+
16+
let rec eval_stmt context stmt =
17+
match stmt with
18+
| Asgn (v_name, expr) ->
19+
Some (v_name, eval context expr)
20+
| Print expr ->
21+
printfn $"{eval context expr}"
22+
None
23+
24+
let eval_prog (statements:list<sourceAst>) =
25+
let context = Dictionary<string, int>()
26+
List.fold
27+
(fun (context:Dictionary<_,_>) stmt ->
28+
let res = eval_stmt context stmt
29+
match res with
30+
| Some (v_name, res) ->
31+
if context.ContainsKey v_name
32+
then context[v_name] <- res
33+
else context.Add(v_name, res)
34+
| None -> ()
35+
context)
36+
context statements
37+
|> ignore
38+
39+
40+

Parsers/Parsers.fsproj

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net7.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<Compile Include="Combinators.fs" />
10+
<Compile Include="AST.fs" />
11+
<Compile Include="ExprParser.fs" />
12+
<Compile Include="Translator.fs" />
13+
<Compile Include="Interpreter.fs" />
14+
<Compile Include="Program.fs" />
15+
</ItemGroup>
16+
17+
</Project>

Parsers/Program.fs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// For more information see https://aka.ms/fsharp-console-apps
2+
3+
open Parsers.Combinators
4+
open Parsers.Interpreter
5+
(*
6+
Parsers.Combinators.run Parsers.Combinators.ident "ab1cd"
7+
|> fun x -> printfn $"{x}"
8+
9+
10+
run (p_list (p_alt (p_char '3') (p_char '5')) (fmap (fun _ -> ()) (p_char ';'))) "5;3;5;3"
11+
|> fun x -> printfn $"{x}"
12+
13+
*)
14+
15+
16+
let res = run Parsers.ExprParser.p_prog "x=2*10+2*3*4+20
17+
var=x+x
18+
print:var*2
19+
print=var*x
20+
print:print"
21+
22+
match res with
23+
| None -> printfn "Incorrect input"
24+
| Some (rest,ast) ->
25+
//printfn $"Res: {res}"
26+
eval_prog ast
27+
28+
29+
(*
30+
let res = run Parsers.ExprParser.p_prog "x=2*10+2*3*4+20
31+
print=x+x
32+
print:print*2"
33+
34+
match res with
35+
| None -> printfn "Incorrect input"
36+
| Some (rest,str) -> printfn $"Res:{str}, rest: {rest}"
37+
*)

Parsers/Translator.fs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Parsers.Translator
2+
open Parsers.AST
3+
4+
let removeUnusedVars (statements:list<sourceAst>) =
5+
//let usedVars =
6+
0

0 commit comments

Comments
 (0)