%{

#include <stdio.h>
#include <stdlib.h>
#include "hiseb.h"

  int dnow, mnow, ynow;
  char *fromnow, *tonow;
  Record table[100];
  int nRow = 0;
  int flag[100];
  Artha tot;
  char *lastComm;
  void addRecord(int y, int m, int d,
                 char *from, char *to,
                 Artha a,
                 char *comm) {
    table[nRow].from = from;
    table[nRow].to = to;
    table[nRow].comm = comm;
    table[nRow].taka.r = a.r;
    table[nRow].taka.p = a.p;
    table[nRow].t.y = y;
    table[nRow].t.m = m;
    table[nRow].t.d = d;
    nRow++;
    lastComm = comm;
  }

  listString* newList() {
    return (listString*) calloc(1,sizeof(listString));
  }

  listString* addString(listString *list, char *str) {
    list->body[list->len] = str;
    (list->len)++;
    return list;
  }
  
  int match(char *patt, char *str) {
    int strstart, pattstart, len;
    
    if(patt[strlen(patt)-1]=='*') {
      strstart = pattstart = 0;
      len = strlen(patt)-1;
    }
    else if(patt[0]=='*') {
      len = strlen(patt)-1;
      strstart = strlen(str)-len;
      pattstart = 1;
    }
    else {
      strstart = pattstart = 0;
      len = strlen(patt);
    }
    return !strncmp(patt+pattstart,str+strstart,len);
  }

  Artha mult(int n, Artha a) {
    Artha c;
    c.r = n*a.r;
    c.p = n*a.p;
    c.r += c.p/100;
    c.p %= 100;
    return c;
  }
  
    Artha addsub(Artha a, int op, Artha b) {
    Artha c;

    if(op<0) {
      b.r = -b.r;
      b.p = -b.p;
    }

    c.r = a.r + b.r;
    c.p = a.p + b.p;
    c.r += c.p/100;
    c.p %= 100;

    return c;
  }

  void dumpRecord(int i, int dir) {
    if(dir==0) return;
    tot = addsub(tot, dir, table[i].taka);
    printf("%s > %s %c%d.%02d %d.%02d (%s on %d/%d/%d)\n",
           table[i].from, table[i].to,
           (dir==-1?'-':' '),table[i].taka.r,table[i].taka.p,
           tot.r, tot.p,
           table[i].comm,
           table[i].t.y, table[i].t.m, table[i].t.d);
    
    printf("\033[0;0m");
  }

  void clearFlag() {
    int i;
    for(i=0;i<nRow;i++)
      flag[i] = 0;
  }
  void setFlag(int i, int val) {
    if(flag[i]==-val) {
      printf("Error: sign clash for %s\n.",table[i].comm);
      exit(1);
    }
    flag[i]=val;
  }  
  void findF(char *from) {
    int i;
    
    for(i=0;i<nRow;i++) {
      if(match(from,table[i].from)) setFlag(i,-1); 
    }
  }

  void findT(char *to) {
    int i;
    
    for(i=0;i<nRow;i++) {
      if(match(to,table[i].to)) setFlag(i,1);
    }
  }

  void findFT(char *from, char *to, int dir) {
    int i;
    
    for(i=0;i<nRow;i++) {
      if(match(from,table[i].from) && match(to,table[i].to)) setFlag(i,dir);
    }
  }


  void showFlagged() {
    int i;
    tot.r = tot.p = 0;
    for(i=0;i<nRow;i++) dumpRecord(i,flag[i]);
    printf("Final balance=\033[0;31m%d.%02d\033[0;0m\n",tot.r,tot.p);

  }

  void line() {
    printf("-----------------------------------------------------------\n");
  }
%}

%union{
  int val;
  char *str;
  Artha kata;
  listString *talika;
}
%token<val> NUM
%token<str> TXT COMM
%type<kata> amt amt1 amt2 amt3
%type<str> from to
%type<talika> lst
%type<val> rup pai
%%
list : elt | list elt;
elt : time | trans | query | COMM;
time : 'y' NUM {ynow=$2;}
| 'm' NUM {mnow = $2; }
| 'd' NUM {dnow = $2;}
trans : from '-'  to amt COMM {addRecord(ynow,mnow,dnow,$1,$3,$4,$5);};
from: {$$ = fromnow;}
    | TXT {fromnow = $1;} 
to: {$$ = tonow;}
    | TXT {tonow = $1;}
amt : amt1
| amt '+' amt1 {$$=addsub($1,1,$3);}
| amt '-' amt1 {$$=addsub($1,-1,$3);}
amt1: amt2
| NUM '#' amt2 {$$=mult($1,$3);}
amt2 : amt3
| '(' amt ')' {$$=$2;}
amt3 : rup {$$.r = $1; $$.p=0;}
    | rup '.' pai {$$.r = $1; $$.p=$3;}
rup: NUM
pai: NUM

query : 'q' lst '?' {
  int i;
  line();
  clearFlag();
  for(i=0;i<$2->len;i++) {
    findF($2->body[i]);
    findT($2->body[i]);
  }
  showFlagged();line();
}
| 'q' lst '-' lst '?' {
  int i,j;
  line();clearFlag();
  for(i=0;i<$2->len;i++) {
    for(j=0;j<$4->len;j++) {
      findFT($2->body[i],
	     $4->body[j],1);
      findFT($4->body[j],
	     $2->body[i],-1);
    }
  }
  showFlagged();line();
  }

lst : TXT {$$ = newList(); addString($$,$1);}
    | lst  TXT {$$ = addString($1,$2);}

%%


int yyerror(char *errMessage) {
   printf("Trouble: %s\n",errMessage);
   printf("after %s\n",lastComm);
   return 1;
}

int main() {
  yyparse();
}
