理系学生日記

おまえはいつまで学生気分なのか

Scheme の構文解析

構文解析つっても構文チェックとか全くしてないのでとてもアレなかんじなんですけど,Scheme っていったら S 式だし,S 式っていったらリストだし,Scheme のソースコードを与えられたら全部 Perl の array reference として返してやったらとりあえず基本構造は作れる.
要は

(define (square x) (* x x))

なんていう Scheme のソースコードが与えられると,

[ 'define', [ 'square', 'x' ], [ '*', 'x', 'x' ] ]

ていう Perl の array reference に変換するみたいな感じですね.だいたいこんな感じの使い方を想定してる.

my $p = Language::Scheme::Parser->new(
    Language::Scheme::Lexer->new( '(define (square x) (* x x))' )->parse
)->parse->dump;
# $VAR1 = [
#           'define',
#           [
#             'square',
#             'x'
#           ],
#           [
#             '*',
#             'x',
#             'x'
#           ]
#         ];

考え方としては,Scheme のコードの '(' とか ')' を Perl の '[',']' に変換した後 eval してやれば良さげ.てわけで,こんな感じの Parser クラスが現状です.

package Language::Scheme::Parser;
use strict;
use warnings;
use Data::Dumper;

sub new {
    my ($class, $aref) = @_;
    bless {
        tokens => $aref
    }, $class
}

sub parse {
    my $self = shift;

    my @substitutes = map { 
        if    ( $_ eq '(' ) { '['       }
        elsif ( $_ eq ')' ) { '],'      }
        else                { qq|'$_',| }
    } @{ $self->{tokens} };
    
    $self->{result} = eval join "", @substitutes;
    $self;
}

sub structure { shift->{result} }

sub dump {
    print Dumper shift->{result}
}

1;