The dot is ignored because the default action (::first) is used for the DOMAIN rule. Mixing the lexer and grammar rules is not a good idea, they're very different. Using consistent capitalization for the non-terminals also helps, I usually use a different rule for the grammar and lexer ones.
I usually build the grammar from the top to the bottom, i.e. from the starting symbol to the L0 rules. I start with the default action of [name,values] and replace it with individual actions from the bottom to the top.
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
use Data::Dump;
use Marpa::R2;
my $dsl = <<'__DSL__';
lexeme default = latm => 1
:default ::= action => ::first
Entry ::= op Hostaddr4 action => entry
Hostaddr4 ::= Hostname action => add_hostname
| Ipv4
Hostname ::= Domains '.' ext action => concat
Domains ::= domain '.' Domains action => concat
| domain
Ipv4 ::= number ('.') number ('.') number ('.') number
action => add_ip
op ~ 'add' | 'remove'
domain ~ [\d\w]+
ext ~ 'org' | 'net'
number ~ [\d]+
:discard ~ whitespace
whitespace ~ [\s]+
__DSL__
my $input = << '__INPUT__';
add example.org
add www.perl.org
add 42.perl.net
add 192.0.2.1
remove 192.0.2.2
__INPUT__
my $grammar = 'Marpa::R2::Scanless::G'->new({source => \$dsl});
open my $in, '<', \$input;
while (<$in>) {
chomp;
next unless length;
say "PARSING: $_";
my $recce = 'Marpa::R2::Scanless::R'->new({
grammar => $grammar,
semantics_package => 'main',
});
# Uncomment for debugging:
# warn $recce->show_progress(0);
$recce->read(\$_);
dd ${ $recce->value };
}
sub add_ip { { type => 'ip', ip => join '.', @_[1 .. $#_] } }
sub concat { shift; join "", @_ }
sub add_hostname { { type => 'hostname', hostname => $_[1] } }
sub entry { { operator => $_[1], %{ $_[2] } } }
__DATA__
PARSING: add example.org
{ hostname => "example.org", operator => "add", type => "hostname" }
PARSING: add www.perl.org
{ hostname => "www.perl.org", operator => "add", type => "hostname" }
PARSING: add 42.perl.net
{ hostname => "42.perl.net", operator => "add", type => "hostname" }
PARSING: add 192.0.2.1
{ ip => "192.0.2.1", operator => "add", type => "ip" }
PARSING: remove 192.0.2.2
{ ip => "192.0.2.2", operator => "remove", type => "ip" }
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]