CPU-Z80-Assembler

 view release on metacpan or  search on metacpan

lib/CPU/Z80/Assembler/Macro.pm  view on Meta::CPAN

# $Id$

package CPU::Z80::Assembler::Macro;

#------------------------------------------------------------------------------

=head1 NAME

CPU::Z80::Assembler::Macro - Macro pre-processor for the Z80 assembler

=cut

#------------------------------------------------------------------------------

use strict;
use warnings;

use CPU::Z80::Assembler::Parser;
use Iterator::Simple::Lookahead;
use Asm::Preproc::Token;

our $VERSION = '2.25';

#------------------------------------------------------------------------------
# Class::Struct cannot be used with Exporter
#use Class::Struct (
#	name	=> '$',			# macro name
#	params 	=> '@',			# list of macro parameter names
#	locals	=> '%',			# list of macro local labels
#	tokens	=> '@',			# list of macro tokens
#);
sub new { my($class, %args) = @_;
	return bless [
				$args{name}, 
				$args{params}	|| [], 
				$args{locals}	|| {}, 
				$args{tokens}	|| []
			], $class;
}
sub name   { defined($_[1]) ? $_[0][0] = $_[1] : $_[0][0] }
sub params { defined($_[1]) ? $_[0][1] = $_[1] : $_[0][1] }
sub locals { defined($_[1]) ? $_[0][2] = $_[1] : $_[0][2] }
sub tokens { defined($_[1]) ? $_[0][3] = $_[1] : $_[0][3] }

#------------------------------------------------------------------------------

=head1 SYNOPSIS

  use CPU::Z80::Assembler::Macro;

  my $macro = CPU::Z80::Assembler::Macro->new(
                  name   => $name,
                  params => \@params_names,
                  locals => \%local_labels,
                  tokens => \@token_list);
  $macro->parse_body($input);
  $macro->expand_macro($input);

=head1 DESCRIPTION

This module provides a macro pre-processor to parse macro definition statements,
and expand macro calls in the token stream. Both the input and output streams
are L<Iterator::Simple::Lookahead|Iterator::Simple::Lookahead> objects returning sequences 
of tokens.

The object created by new() describes one macro. It is used during the parse phase
to define the macro object while reading the input token stream.

=head1 EXPORTS

None.

=head1 FUNCTIONS

=head2 new

Creates a new macro definition object, see L<Class::Struct|Class::Struct>.

=head2 name

Get/set the macro name.

=head2 params

Get/set the formal parameter names list.

=head2 locals

Get/set the list of local macro labels, stored as a hash.

=head2 tokens

Get/set the list of tokens in the macro definition.

=cut

#------------------------------------------------------------------------------

=head2 parse_body

This method is called with the token input stream pointing at the first token
after the macro parameter list, i.e. the '{' or ':' or "\n" character.

It parses the macro body, leaving the input stream after the last token of the
macro definition ('endm' or closing '}'), with all the "\n" characters of the
macro defintion pre-pended, and filling in locals() and tokens().

=cut

#------------------------------------------------------------------------------

lib/CPU/Z80/Assembler/Macro.pm  view on Meta::CPAN

			$input->next;
		}
	}
	
	# expect end of statement, keep input at end of statement marker
	$token = $input->peek;
	(!defined($token) || $token->type =~ /^[:\n]$/)
		or Asm::Preproc::Token->error_at($token, "too many macro arguments");
	
	return \%args;
}

#------------------------------------------------------------------------------
# @tokens = _parse_argument($input)
#	Extract the sequence of input tokens from $input into @tokens up to and
#	not including the delimiter token
sub _parse_argument {
	my($class, $input) = @_;
	my $token;	

	# retrieve tokens
	my @tokens;
	my $parens = 0;
	my $opened_brace;
	while (defined($token = $input->peek)) {
		my $type = $token->type;
		if ($type =~ /^[:\n,]$/ && $parens == 0) {
			last;
		}
		elsif ($type eq '{') {
			$parens++;
			push(@tokens, $token) if $opened_brace++;
			$input->next;
		}
		elsif ($type eq '}') {
			if ($parens > 0) {
				$parens--;
				push(@tokens, $token) if --$opened_brace;
				$input->next;
			}
			else {
				$input->next if $opened_brace;		# skip delimiter
				last;
			}
		}
		else {
			push(@tokens, $token);
			$input->next;
		}
	}
	Asm::Preproc::Token->error_at($token, "unmatched braces") 
		if $parens != 0;

	return @tokens;
}

#------------------------------------------------------------------------------

=head1 SYNTAX

=head2 Macros

Macros are created thus.  This example creates an "instruction" called MAGIC
that takes two parameters:

    MACRO MAGIC param1, param2 {
        LD param1, 0
        BIT param2, L
        label = 0x1234
        ... more real instructions go here.
    }

Within the macro, param1, param2 etc will be replaced with whatever
parameters you pass to the macro.  So, for example, this:

    MAGIC HL, 2

Is the same as:

    LD HL, 0
    BIT 2, L
    ...

Any labels that you define inside a macro are local to that macro.  Actually
they're not but they get renamed to _macro_NN_... so that they
effectively *are* local.

There is an alternative syntax, for compatibility with other assemblers, with exactly the
same effect.

    MACRO MAGIC param1, param2
        LD param1, 0
        BIT param2, L
        label = 0x1234
        ... more real instructions go here.
    ENDM

A ',' can be passed as part of a macro argument, by enclosing the arguments between {braces}.

    MACRO PAIR x {
        LD x
    }
    PAIR {A,B}

expands to:

    LD A,B

=head1 BUGS and FEEDBACK

See L<CPU::Z80::Assembler|CPU::Z80::Assembler>.

=head1 SEE ALSO

L<CPU::Z80::Assembler|CPU::Z80::Assembler>
L<Iterator::Simple::Lookahead|Iterator::Simple::Lookahead>

=head1 AUTHORS, COPYRIGHT and LICENCE

See L<CPU::Z80::Assembler|CPU::Z80::Assembler>.

=cut



( run in 0.417 second using v1.01-cache-2.11-cpan-ceb78f64989 )