Index: lib/Makefile
===================================================================
--- lib/Makefile	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
+++ lib/Makefile	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
@@ -0,0 +1,19 @@
+include ../config.mak
+
+.PHONY: install
+install:
+ifdef LIB_DIR
+	install -m 0755 attr.pm $(LIB_DIR)
+	install -m 0755 seg.rb $(LIB_DIR)
+	install -m 0755 ser.l.template $(LIB_DIR)
+	install -m 0755 terms.m4 $(LIB_DIR)
+endif
+
+.PHONY: uninstall
+uninstall:
+ifdef LIB_DIR
+	rm $(LIB_DIR)/attr.pm
+	rm $(LIB_DIR)/seg.rb
+	rm $(LIB_DIR)/ser.l.template
+	rm $(LIB_DIR)/terms.m4
+endif
Index: lib/attr.pm
===================================================================
--- lib/attr.pm	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
+++ lib/attr.pm	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
@@ -0,0 +1,133 @@
+package attr;
+
+use locale;
+use strict;
+
+use Data::Dumper;
+
+our $pos_re    = qr/(?:[[:upper:]]+)/;
+our $attr_re   = qr/(?:[[:upper:]]+)/;
+our $val_re    = qr/(?:[[:lower:][:digit:]+?!*-]|<[^>\n]+>)/;
+our $av_re     = qr/(?:$attr_re$val_re+)/;
+our $avlist_re = qr/(?:$av_re+)/;
+our $cat_re    = qr/(?:$pos_re(?:\/$avlist_re)?)/;
+
+sub match(\@\@)
+{
+    my ($cat1,$avs1)= @{shift @_};
+    my ($cat2,$avs2)= @{shift @_};
+
+    if($cat1 ne $cat2 && $cat1 ne '*' && $cat2 ne '*')
+    {
+	return 0; 
+    }
+    else
+    {
+      ATTR:for my $attr (keys %$avs1)
+      {
+	  if(exists $avs2->{$attr})
+	  {
+	      for my $val (keys %{$avs1->{$attr}})
+	      {
+		  next ATTR if $avs2->{$attr}->{$val};
+	      }
+	      return 0;
+	      last ATTR;
+	  }
+      }
+    }
+
+    return 1;
+}
+
+sub agree(\@\@$)
+{
+    my $val1 = $_[0]->[1]->{$_[2]};
+    my $val2 = $_[1]->[1]->{$_[2]};
+
+    return 1 if !$val1 || !$val2;
+
+    for my $v (keys %$val1)
+    {
+	return 1 if exists $val2->{$v};
+    }
+    return 0;
+}
+
+# funkcja parse
+# arg:     deskrypcja
+# warto¶æ: referencja do tablicy [<cat>, <avs>],
+#          gdzie <avs> jest referencja do hasza, zawierajacego pary
+#          atrybut=>hasz warto¶ci (pary warto¶æ=>1), czyli np.
+
+#         [
+#           'ADJ',
+#           {
+#             'KOLEDZY' => {
+#                            '<alojzy>' => 1,
+#                            '<karol>' => 1,
+#                            '<jan>' => 1
+#                          },
+#             'C' => {
+#                      'p' => 1,
+#                      'a' => 1,
+#                      'i' => 1
+#                    },
+#             'N' => {
+#                      'p' => 1
+#                    }
+#           }
+#         ];
+
+sub parse ($)
+{
+    my ($dstr)=@_;
+    my $avs={};
+    my ($cat,$attrlist) = split '/', $dstr;
+  ATTR:
+#    while( $attrlist =~ /([[:upper:]]+)((?:[[:lower:][:digit:]+?!*-]|<[^>\n]+>)+)/g )
+    while( $attrlist =~ /($attr_re)($val_re+)/g )
+    {
+	my ($attrstr,$valstr)=($1,$2);
+	my %vals;
+	while($valstr =~ /$val_re/g)
+	{
+	    my $val = $&;
+	    next ATTR if $val eq '*';
+	    $val =~ s/^<([[:lower:]])>$/$1/;
+	    $vals{$val}=1;
+	}
+	
+	$avs->{$attrstr} = \%vals; # dlaczego to dziala? %vals jest lokalne
+    }
+    [$cat, $avs];
+}
+
+# funkcja unparse
+# arg:     jak warto¶æ parse
+# warto¶æ: deskrypcja - napis
+
+sub unparse (\@)
+{
+    my ($cat,$avs)= @{shift @_};
+    my $dstr=$cat;
+    my @attrs = keys %$avs;
+    if(@attrs)
+    {
+	$dstr .= '/';
+	for my $attr ( sort @attrs )
+	{
+	    $dstr .= $attr . (join '', sort keys %{$avs->{$attr}});
+	}
+    }
+    $dstr;
+}
+
+
+sub canonize ($)
+{
+    unparse @{parse @_[0]} ;
+}
+
+
+1;
Index: lib/seg.rb
===================================================================
--- lib/seg.rb	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
+++ lib/seg.rb	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
@@ -0,0 +1,31 @@
+
+class Seg
+  
+  def initialize(s="")
+    @line=s
+    self
+  end
+
+  def to_s
+    @line.chomp
+  end
+
+  def set(s)
+    @line=s
+    self
+  end
+
+  def field(key)
+    if key.class==Fixnum
+      @line.split[key-1]
+    elsif key.class==String
+      @line =~ /\s#{key}:(\S+)/; $1
+    end
+  end
+  alias [] field
+
+  def fields
+    @line.split
+  end
+
+end
Index: lib/ser.l.template
===================================================================
--- lib/ser.l.template	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
+++ lib/ser.l.template	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
@@ -0,0 +1,30 @@
+%{
+		#include<string.h>
+		int n=0;
+%}
+
+%%
+
+PATTERN			{
+			  int start, end, len;
+			  char *lastseg, *tmp;
+			  if(yytext[yyleng-1]!='\n')
+			    {fprintf(stderr,"ser: pattern matches incomplete line\n"); exit(1);}
+			  n++;
+			  sscanf(yytext,"%d %d",&start,&len);
+			  yytext[yyleng-1]='\0';
+			  if(tmp=strrchr(yytext,'\n'))
+			  {
+			    lastseg=tmp+1;
+			    sscanf(lastseg,"%d %d", &end, &len);
+			  }
+			  else
+			    end=start;
+			  yytext[yyleng-1]='\n';
+			  printf("%04d 00 BOM * ser:%d\n",start,n);
+			  ECHO;
+			  printf("%04d 00 EOM * ser:%d\n",end+len,n);
+			}
+
+
+.*\n			DEFAULTACTION;
Index: lib/terms.m4
===================================================================
--- lib/terms.m4	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
+++ lib/terms.m4	(revision 5f4d9c3b32eea7b6643a751aa75bdb05b7d41576)
@@ -0,0 +1,52 @@
+divert(-1)
+#--------------------------------------------------------------------------
+
+# Macros defined here may be used in pattern specifications 
+# You can modify this file according to your needs.
+
+# ENDOFSEGMENT and MORFIELD are macros expanded to, respectively,
+# end of segment marker (dependes on the format: flattened or not)
+# and the name of the annotation field containing morphological
+# information (standard value is 'lem'). These values are controlled
+# by programs using this file to expand search patterns (ser, grp, ...).
+
+# seg(type,form,annotation) 
+
+define(`seg',`(\s*((\d+\s+)(\d+\s+)?)?dnl
+ifelse($1, `',`(\S+)', `($1)')\s+dnl
+ifelse($2, `',`(\S+)', `($2)')dnl
+ifelse($3, `',`((\s+\S+)*)', `(\s+($3))')\s*ENDOFSEGMENT)')
+
+# form(f) - segment containing the form f 
+
+define(`form', `seg(,$1)')
+
+# field(f) segment containing auxiliary field f 
+
+define(`field', `seg(,,`(\S+\s+)*($1)(\s+\S+)*')')
+
+# word, space, punct, number segments (assuming W, S, P, N segment types)
+
+define(`space', `seg(`S',`$1')')
+define(`word',  `seg(`W',`$1')')
+define(`punct', `seg(`P',`$1')')
+define(`number', `seg(`N',`$1')')
+
+# macros specific to PMDB format 
+
+define(`lexeme', `field(`MORFIELD:(\S+;)?$1,\S+')')
+define(`cat', `field(`MORFIELD:\S+,$1([,;]\S+)?')')
+
+
+# Place here your macro definitions. 
+
+
+
+
+
+
+
+
+
+#--------------------------------------------------------------------------
+divert(0)
