Patch title: Release 94 bulk changes
Abstract:
File: /pliant/sample/parser.pli
Key:
    Removed line
    Added line
# Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# 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
# version 2 along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


abstract
  [This file contains a new trivial Pliant parser intended to illustrate how to change the Pliant parsing mechanism.]

doc
  para
    [A parser is composed of two stages:]
    list
      item [a set of filters that will recognize token on the source code, put them at the end of list and forward the cursor]
      item [some folding functions (operators) that can be attached to the token by the filters, and that will fold operators, in order to move from a list to a tree, during the second stage of the parsing]
  para
    [The main entry of the parser an object named 'pliant parser sections' in the main Pliant dictionary, which must contain a list of strings. ]
    [Each string is the name of an identifier that will be scanned in the main dictionary in order to find the various token filter.]
  para
    [From a logical point of view, a parser is simply a list of filters. This complex structure with a list of sections each of them containing a set of structures, each of it pointing to a filter function is only intended to help to order the various filters (some must take place before others) and to allow module inclusion to enable or disable some of the filters.]


module "/pliant/language/parser.pli"
module "/pliant/language/compiler.pli"

doc
  [Wa start through creating the list of sections for the new parser]

gvar List sections

doc
  [and define a single section in it. (Please notice that the name of the sections must be complicated (contain a space) in order to avoid potential name clashes with other applications)]

sections append addressof:(new Str "new_parser first_section")

doc
  [This is a sample parser filter: it scans the 'line' which is the string containing all the characters still to be parsed on the currently parsed line.]

function parse_identifier context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  var Int i := 0
  while i<line:len and (line:i>="a" and line:i<="z" or line:i>="A" and line:i<="Z")
    i += 1
  if i>0
    var Link:Ident t :> new Ident
    t := cast (line 0 i) Ident
    context add_token addressof:t
    context forward i

doc
  [in order to use this parser filter in the new parser, we have to record it with the name of section it belongs to. Also we don't record the function itself, but rather a structure which has a pointer to the function as one of it's arguments.]

gvar ParserFilter identifier_filter
identifier_filter function :> the_function parse_identifier ParserContext Str Address
constant 'new_parser first_section' identifier_filter

doc
  [These are a two other filters in order to parse comments and various spaces]

function parse_c_like_comments context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  if (line 0 2)="//"
    context forward line:len

gvar ParserFilter comment_filter
comment_filter function :> the_function parse_c_like_comments ParserContext Str Address
constant 'new_parser first_section' comment_filter


function parse_various_spaces context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  if (line 0 1)=" " or (line 0 1)="[tab]"
    context forward 1

gvar ParserFilter space_filter
space_filter function :> the_function parse_various_spaces ParserContext Str Address
constant 'new_parser first_section' space_filter

doc
  [Now we define the '(' and ')' operators:]

function parse_brackets context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  if (line 0 1)="("
    context open_sublevel "()"
    context forward 1
  eif (line 0 1)=")"
    context close_sublevel "()"
    context forward 1

gvar ParserFilter brackets_filter
brackets_filter function :> the_function parse_brackets ParserContext Str Address
constant 'new_parser first_section' brackets_filter

doc
  [and the '==' operator:]

function fold_binary_operator arguments index parameter
  arg_rw Array arguments ; arg Int index ; arg Address parameter
  fold_arguments arguments index 1 null 1 null
  # index is the position of the operator in the array of expressions
  # fold arguments will take, for each side (left and right), the number
  # of arguments to be folded, and eventually an object that would be
  # the value of a new expression that would be inserted between the
  # operator and it's arguments (providing null will not insert any
  # object in the middle and is what you probably want)

function parse_equal context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  if (line 0 2)="=="
    var Link:Ident t :> new Ident
    t := cast "==" Ident
    var Link:Expression e :> context add_token addressof:t
    var Link:ParserOperator o :> new ParserOperator
    e operator :> o
    o function :> the_function  fold_binary_operator Array Int Address
    o priority := 100
    context forward 2

gvar ParserFilter equal_filter
equal_filter function :> the_function parse_equal ParserContext Str Address
constant 'new_parser first_section' equal_filter

alias '==' '='
alias '==' '=' from "/pliant/language/basic/safe.pli"

doc
  [We assume that in our sample parser, the ';' sign means that the instruction or definition is complete, so we can compile and execute it:]

function parse_eol context line parameter
  arg_rw ParserContext context ; arg Str line ; arg Address parameter
  if (line 0 1)=";"
    context forward 1
    context execute

gvar ParserFilter eol_filter
eol_filter function :> the_function parse_eol ParserContext Str Address
constant 'new_parser first_section' eol_filter

doc
  [The sample parser is now complete, so we can define the new parser section list.] ; eol
  [This must be done at the end since it will replace the old parser for every module that include this one, ]
  [so it must be complete because it will be used to parse the end of this one module (which defaultly include itself like any other module)]

constant 'pliant parser sections' sections ; export 'pliant parser sections' ; export 'new_parser first_section'

// right now the new parser is active
true == false ;