2017-11-25 191 views
0

我想研究解释器和编译器的基础知识,使用F#和FsLexYacc库,但是我很难理解编写Lexer和Parser文件的原则......我正在关注this example,但它为iterpreter使用了一些简单的SQL查询。我在寻找的是如何使用F#将this grammar转换为有效的Lexer和Parser。 如果有帮助,我会包含我的AST,Lexer和Parser文件。FsLexYacc。用F#和Leading分析和解析#

这是AST

module Ast 


type TypeIdentifier = 
    |Boolean of bool 
    |Integer of int 
    |Float of float 
    |String of string 

and BinaryOperators = 
    |Add 
    |Subtract 
    |Multiply 
    |Equal 
    |NotEqual 
    |Less 
    |Greater 
    |LessEqual 
    |GreaterEqual 
    |Semicolon 
    |Colon 
    |Range 
    |Assign 

这是词法

{ 
module SqlLexer 
open System 
open SqlParser 
open Microsoft.FSharp.Text.Lexing 

let keywords = [ 

    "div", DIV; 
    "or", OR; 
    "and", AND; 
    "not", NOT; 
    "if", IF; 
    "then", THEN; 
    "else", ELSE; 
    "of", OF; 
    "while", WHILE; 
    "do", DO; 
    "array", ARRAY; 
    "procedure", PROCEDURE; 
    "program", PROGRAM; 
    "begin", BEGIN; 
    "end", END; 
    "var", VAR 

] |> Map.ofList 

let ops = [ 

    "+", ADD; 
    "-", SUBTRACT; 
    "*", MULTIPLY; 
    "=", EQUAL; 
    "<>", NOTEQUAL; 
    "<", LESS; 
    "<=", LESSEQUAL; 
    ">", GREATER; 
    ">=", GREATEREQUAL; 
    ":=", ASSIGN; 
    ".", POINT; 
    ",", COMMA; 
    ";", SEMICOLON; 
    ":", COLON; 
    "..", RANGE; 

] |> Map.ofList 
} 

let char    = ['a'-'z' 'A'-'Z'] 
let digit    = ['0'-'9'] 
let int     = '-'?digit+ 
let float    = '-'?digit+ '.' digit+ 
let identifier   = char(char|digit)* 
let whitespece   = [' ' '\t'] 
let newline    = "\n\r" | '\n' | '\r' 
let operator   = "+" | "-" | "*" | "=" | "<>" | "<" | "<=" | ">" | ">=" | ":=" | "." | "," | ";" | ":" | ".." 

rule tokenize = parse 
| whitespace  { tokenize lexbuf } 
| newline   { lexbuf.EndPos <- lexbuf.EndPos.NextLine; tokenise lexbuf; } 
| int    { INT(Int32.Parse(LexBuffer<_>.LexemeString lexbuf)) } 
| float    { FLOAT(Double.Parse(LexBuffer<_>.LexemeString lexbuf) } 
| operator   { ops.[LexBuffer<_>.LexemeString lexbuf] } 
| identifier  { match keywords.TryFind(LexBuffer<_>.LexemeString lexbuf) with 
         | Some(token) -> token 
         | None -> ID(LexBuffer<_>.LexemeString lexbuf)} 
| eof    { EOF } 

这是我的解析器:

%{ 
open Sql 
%} 

%token <string> ID 
%token <int> INT 
%token <float> FLOAT 
%token <bool> BOOL 

%token DIV 
%token AND OR NOT 
%token IF THEN ELSE 
%token WHILE DO 
%token ARRAY OF 
%token PROGRAM 
%token PRODEDURE 
%token BEGIN END 
%token VAR 

%token ADD SUBTRACT MULTIPLY 
%token EQUAL NOTEQUAL 
%token LESS LESSEQUAL 
%token GREATER GREATEREQUAL 
%token ASSIGN 
%token POINT COMMA RANGE 
%token SEMICOLON COLON 

%start start 

start: 
    PROGRAM ID ; 
    block . 
    EOF { 
     identifier = {$2} 
     block = {$4} 
    } 

block: 
    |variableDeclarationPart procedureDeclaretionPart statementPart {$1, $2, $3} 

variableDeclarationPart: 
    | {} 
    |VAR variableDeclaration ; {variableDeclaration;} {} 

我不写代码寻找一个答案,我会像一些类似的例子的解释或者使用FsLexYacc库来解释编程语言的教程帕斯卡

回答

1

我一直在努力与此相当一段时间。我最终做的是,由于FsLexYacc库基于lex和yacc,我已经通过了关于bare lex和yacc(或flex bould)的快速教程,除了不使用C语法,我将它转换为F#并使用它在我的测试项目中。 通过我经历了 https://github.com/fsprojects/FsLexYacc/blob/master/docs/content/jsonParserExample.md的概念后,我做了一些深奥的语言。

希望这会有所帮助。

PS:F#编译器是开源的,它使用了FsLexYacc,所以你也可以尝试读取这些东西。