2017-11-25 229 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,所以你也可以嘗試讀取這些東西。