/* -*- mode: tuareg -*- */ /* Bicicleta language interpreter Copyright (C) 2007 Kragen Javier Sitaker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA */ %{ open Bicicleta_syntax;; (* Reorder the definitions so the earliest ones are outermost; there's no semantic reason for this, but changing it would require changing the existing parse regression tests, and also show_bicexpr. It's also a convenient place to add names for positional arguments. *) let mk_defs deflist = let rec fd_defs argcount = function [] -> NoDefs | (Some name, expr) :: defs -> Definition(name, expr, false, fd_defs argcount defs) | (None, expr) :: defs -> Definition("arg" ^ string_of_int argcount, expr, true, fd_defs (argcount + 1) defs) in fd_defs 1 (List.rev deflist) ;; %} %token NameTok %token StringTok %token OpTok %token IntTok %token FloatTok %token Lparen Rparen Lbrace Rbrace Colon Period Newline Comma Equals Eof %token Lsquare Rsquare /* As written, this grammar has five ambiguities: is 1 + 2 + 3 supposed to be (1 + 2) + 3 or 1 + (2 + 3), and is 1 + x(3) supposed to be 1 + (x(3)) or (1 + x)(3) (with equivalent cases for 1+x[3], 1+x{3}, and 1+x.y)? The first one is resolved with %left OpTok below, and the others are resolved with the %nonassoc declaration, which gives those tokens higher precedence than OpTok by virtue of coming later in the source file. ocamlyacc -v is helpful for diagnosing this! */ %left OpTok %nonassoc Period Lparen Lbrace Lsquare %start main %type main %% /* 23 productions --- a fairly small grammar. If you try to write a grammar for Common Lisp, you end up with 16 productions to handle lists, dotted pairs, symbols, strings, integers, floats, ratios, chars, quote, quasiquote, unquote, unquote-splicing, and vectors, but that leaves out #=, ##, #*, #:, #|...|#, #+, #-, #., #a, #c, #b, #o, #x, #r, $p, #s, ",.", and user-defined read macros. Also, some macros are pretty hairy; the CLHS entry for LOOP has a BNF grammar with 34 nonterminals. */ main: expr Eof { $1 } expr: expr Period NameTok { Call($1, $3) } | NameTok { Name $1 } | StringTok { StringConstant $1 } | literal { Literal(fst $1, snd $1) } | expr literal { Derivation($1, fst $2, snd $2) } | expr Lparen definitions Rparen { Call(Derivation($1, None, mk_defs $3), "()") } | expr Lparen NameTok Colon definitions Rparen { Call(Derivation($1, Some $3, mk_defs $5), "()") } | expr Lsquare definitions Rsquare { Call(Derivation(Call($1, "[]"), None, mk_defs $3), "()") } | Lparen expr Rparen { $2 } | IntTok { Integer (int_of_string $1) } | FloatTok { Float (float_of_string $1) } | expr OpTok expr { Call(Derivation(Call($1, $2), None, mk_defs [None, $3]), "()") } literal: Lbrace NameTok Colon definitions Rbrace { ((Some $2), mk_defs $4) } | Lbrace definitions Rbrace { (None, mk_defs $2) } definitions: NameTok Equals expr { [Some $1, $3] } | definitions def_separator NameTok Equals expr { (Some $3, $5) :: $1 } | expr { [None, $1] } | definitions def_separator expr { (None, $3) :: $1 } | /* empty */ { [] } def_separator: Comma { () } | Comma Newline { () } | Newline { () }