%{/*This bison/yacc program parses the Formalised English (FE) linear format
    used in WebKB-1 (now superseded by WebKB-2)
    (see http://meganesia.int.gu.edu.au/~phmartin/WebKB/doc/grammars/)
    and translates it into a CG linear format (there is no official grammar
    for this grammar; for new/uncommon features, we used a format close to
    the FE format).     
    Author: Philippe.Martin@gu.edu.au; Creation date: 25/11/99
     Test: http://meganesia.int.gu.edu.au/~phmartin/WebKB/doc/grammars/kbfe.html
yes:A cat is on a mat which is near a table, and has for color the white.
no: A cat is on a mat which is near a table, and has for color the white, and for r a t.
yes: Joe is a smoker and is a driver.
no: Joe is a smoker and a driver.
yes: Joe has for type Smoker and for type Driver.

Compilation:
fe: fe.o
	$(C++) $(OPTLINK) -o fe fe.o
fe.o: fe.c
	$(C++) $(OPTIONS) -c fe.c -o fe.o
fe.c: fe.y fe.lex.c
	bison -pfe -v -t -y fe.y -o fe.c
fe.lex.c: fe.l
	flex -Pfe -i fe.l; /bin/mv lex.fe.c fe.lex.c

To debug, set "yydebug=1;" in main()  (by default: #define YYDEBUG 1)
   */
#ifndef __cplusplus
#define __cplusplus
#endif
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include "String.h"

#include "fe.lex.c"
#define YYERROR_VERBOSE 1
#define pr printf

int feerror(const char *s); 
extern "C" int   isFormalisedEnglish (char *arg0, char *arg1);
extern "C" char *formalisedEnglishToCGs (char *fe); /* at end of this file */

#ifdef _IN_WEBKB
extern int WithTrace; extern char ParsingError[];
extern "C" char KsIsaRelationType (char *rTn1);
int isUndeclTermEndingByING (String relName)
{ char *r=(char *)(relName.chars());  int l=strlen(r)-1;
  return ((tolower(r[l])=='g') && (tolower(r[l-1])=='n') &&
          (tolower(r[l-2])=='i') && !KsIsaRelationType(r));
}
#else
int WithTrace=1; char ParsingError[500];
int isUndeclTermEndingByING (String relName)
{ char *r=(char *)(relName.chars());  int l=strlen(r)-1;
  return ((tolower(r[l])=='g') && (tolower(r[l-1])=='n') &&
          (tolower(r[l-2])=='i'));
}
/* plus function main() at end of file because yydebug undeclared here */
#endif


String FEinCGs;  /* the result of the parsing */
static String FE_LastToken,  RelType, Qualifier;
static String Indiv, Coref, Set,   Term, Num,N1, Perc;
static String BrIndent("");  static int Of=0, IsIndiv=0;
static void IndentS(int nbC) 
{ BrIndent="    ";
  while (--nbC>0) BrIndent+="              "; }
static String IsIt;

#define MAX_DEPTH 20
static int D=0;  /*Tree depth*/
static String FEinCG[MAX_DEPTH], Tree[MAX_DEPTH];
static String Concept[MAX_DEPTH], ConCore[MAX_DEPTH], Annot[MAX_DEPTH];
static String Relation[MAX_DEPTH], Elem[MAX_DEPTH], Collec[MAX_DEPTH];
static String Cq[MAX_DEPTH], Restrictor[MAX_DEPTH], ConType[MAX_DEPTH];
static String Quantif[MAX_DEPTH], CorefI[MAX_DEPTH], GroupOf[MAX_DEPTH];
static int InCollec[MAX_DEPTH];
/* static String b, Query, DefinedType, Concept[MAX_DEPTH], Relation[MAX_DEPTH];
static int IsADef=0;*/

typedef struct _StringList StringList;
struct _StringList { String object; StringList *next; };
static StringList *Branch[MAX_DEPTH], *Branches[MAX_DEPTH];
/* functions to manage string lists: */
StringList *newS(); void delS(StringList *me);
void pushS(StringList *me, String str); String popS(StringList *me);
int isEmptyS(StringList *me);
String StringRelation (String relName); 
void upInitial(/*varP*/char *str); void delLastS (/*varP*/char *str);

static void mkFEinCG (int isNegated);
static void mkTree (); static void mkBranch(int isAdef);
static void mkRel (int isImplication); static void mkRelC (int isImplication);
static void mkRelOp (char *oper);
static void mkConcept (); static void mkConCore (int conCoreCase);
static int  isIdentInString(char *s);

#if 0
<a href="http://www.stud.ifi.uio.no/~lmariusg/download/artikler/bnf.html"></a>
Extended BNF grammar for Frame-CGs
("?" means 0 or 1 times, "*" means 0 to N times, "+" means 1 to N times):

FE           := (Tree ("."|"?"))+

Tree         := Concept Branches*
QuotedTree   := "~"? "`" Tree "'" Context?
Context      := "(" Branches2 ")"

Branches     := With  Relation1 Tree (And With? Relation Tree)*
              | With? Relation2 Tree (And With? Relation Tree)*
              | "is"("a"|"an")Tree (And "is"("a"|"an")Tree)*
Branches2    := With? Relation Tree (And With? Relation Tree)*
              | "is"("a"|"an") Tree (And "is"("a"|"an") Tree)*
With         := ("with"|"at"|"has for"|"have for"|"for"|"is"|"are"|
                 ("can"|"may")("be"|"have for")) "the"?
And          := "and" | ","

Relation     := Relation1 | Relation2
Relation1    := (RelationType|Coreference) "of"? Annotation? Context? "<="?
Relation2    := ("=>" | "<=>" | "<=" ) Concept
              | ("=" | "!=" | "<" | "=<" | ">" | ">=" | "or") Concept
RelationType := Term_or_string
Coreference  := "*" Term_or_number

Concept      := ConceptCore Annotation? 

ConceptCore  := CorefOrIndiv Quantifier  Restrictor               CQ?
              |              Quantifier  Restrictor CorefOrIndiv? CQ?
              | GroupOf      Quantifier? Restrictor CorefDecl?    Collection?
              | GroupOf      Quantifier?            CorefDecl?    Collection
              | (Number | "~"Coreference  |  CQ  |  CorefOrIndiv  CQ?)
CorefOrIndiv := CorefDecl
              | "named"? Term_or_string ("\\" ConceptType)?
                  //Term_or_string: individual (ex: Tom) or attribute (ex: high)
CorefDecl    := "*"Term_or_number  
              | "*"Term_or_number "!=" "*"Term_or_number 
              | "*"Term_or_number "!=" Term_or_number
CQ           :=  Collection | QuotedTree

Restrictor   := Qualifier? ConceptType 
              | Qualifier? "[" ConceptType Branches "]"
ConceptType  := Term_or_string
Qualifier    := "good"|"bad" | "important"|"small"|"big"|"great" | "certain"

Quantifier   := "a" | "an" | "some" | "the" 
              | "any" | "every" | "most" "of"? "the"? 
              | "at" "least" Number "%"? "of"? "the"?
              | "at" "most"  Number "%"? "of"? "the"?
              | "between" Number "%"? "and" Number "%"? "of"? "the"?
              |           Number "to"  Number "%"? "of"? "the"?
              | "from"    Number "to"  Number "%"? "of"? "the"?
              | "mostly" | "several" "of"? "the"?
              | Number "%"? "of"? "the"?
              | ("many"|"few"|"dozens"|"hundreds"
                       |"thousands"|"millions"|"billions") "of"? "the"?

GroupOf      := CorefOrIndiv?("a"|"the")("group""of" | "bag""of" |
                                         "set""of"|"sequence""of"|"alternative")
              | "together"
Collection   := "{" (Set|Bag|OrderedSet|OrderedBag|XOR_Set|OR_Bag) "}" CollSize?
Set          := Element (","  Element)*
Bag          := Element ("&"  Element)*
OrderedSet   := Element ("<"  Element)*
OrderedBag   := Element ("=<" Element)*
XOR_Set      := Element ("/"  Element)*
OR_Bag       := Element ("|"  Element)*
Element      := Concept | "*"
CollSize     := "@" Number

Term_or_number:= Term | number
Term_or_string:= Term | string
Term          := TermLetter1 TermLetter*
TermLetter1   := [a-z] | "#"[a-z]
TermLetter    := [a-z] | "#" | "_" | "-" | "/" | "?" | "&" | "~"
               | Digit
               | [.?][a-z0-9?#~]  //thus "." ok within a term but not at the end
               | "://"            //thus a URL may be a term
Number        := ("+"|"-")? Digit+ ("." Digit* )?
Digit         := [0-9]

//Additional notes on the lexical parsing:
- uppercase letters are parsed as if they were lowercase letters
- white spaces and the HTML imbreakable space encoding "&nbsp;" are ignored
- Java/C++ comments ("/* ... */" and "//...") are ignored
- HTML tags are ignored but the content of HTML comments is parsed
- annotations are enclosed within "(^" and "^)"
- strings may be double quoted or enclosed within "$(" and ")$" (<b>because of
  the use of quotes and bacquotes to embedd sentences, strings cannot also be
  simple quoted in FE</b>)
#endif
%}



/* declarations for formalisedEnglish.l */
%token IDENTIFIER NUMERAL STRING ANNOTATION   NAMED
%token BOB WITH AT HAS_FOR CAN_HAVE_FOR MAY_HAVE_FOR  IS_A  A SOME THE CERTAIN
%token SEVERAL EVERY ALL AT_LEAST AT_MOST BETWEEN FROM TO MANY MOST MOSTLY
%token AND OF NOT_EQUAL LTE IMPLIED_BY OTHER_OPERATOR
%token GROUP_OF BAG_OF SET_OF SEQUENCE_OF ALTERNATIVE TOGETHER
%token DOZENS HUNDREDS THOUSANDS MILLIONS BILLIONS 
%token GOOD BAD IMPORTANT SMALL BIG GREAT FEW
%start FE

%%

FE         : SENTENCE EOS {++D} FE {FEinCGs=IsIt+FEinCG[--D]+";\n\n"+FEinCGs;
                                    InCollec[D]=0;  FE_LastToken="";}
           | error    EOS {++D} FE {FEinCGs="";InCollec[--D]=0;FE_LastToken="";}
           |                       {FEinCGs="";InCollec[D]=0;FE_LastToken="";}
           ;

SENTENCE   :                          TREE                {FEinCG[D]= Tree[D];
#ifndef _IN_WEBKB
 pr("mkFEinCG-:%s.\n",FEinCG[D].chars());
#endif
}
           ;
Q_SENTENCE :     '`' {InCollec[D]=0;} TREE '\'' _CONTEXT  {mkFEinCG(0);}
           | '~' '`' {InCollec[D]=0;} TREE '\'' _CONTEXT  {mkFEinCG(1);}
           ;

TREE       : CONCEPT EOT                          {Tree[D]= Concept[D];}
           | CONCEPT BRANCH_1 _BRANCHES_N EOT     {mkTree();}
           ;
BRANCH_1   : IS_WITH RELATION1 {++D;} TREE        {--D; mkBranch(0);}
BRANCH_1   :   _WITH RELATION2 {++D;} TREE        {--D; mkBranch(0);}
           | IS_A              {++D;} TREE        {--D; mkBranch(1);}
           ;
BRANCH_N   : BOB                                  {/*BOB:= "_,_" | "_and_"*/}
           | BOB _WITH RELATION {++D;}TREE        {--D; mkBranch(0);}
           | BOB  IS_A          {++D;}TREE        {--D; mkBranch(1);}
           ;
_WITH      : | IS_WITH;
IS_WITH    : WITH | AT | HAS_FOR | CAN_HAVE_FOR | MAY_HAVE_FOR
           ;
_BRANCHES_N: 
           | BRANCH_N _BRANCHES_N          {pushS(Branches[D],popS(Branch[D]));}
           ;


BRANCH_1C  : _WITH    RELATION {++D;} TREE        {--D; mkBranch(0);}
           |  IS_A             {++D;} TREE        {--D; mkBranch(1);}
           ;
_CONTEXT   :
           | '(' {++D;} BRANCH_1C _BRANCHES_N ')' {--D;}
           ;


RELATION   : RELATION1 | RELATION2
           ;
RELATION1  : REL_TYPE    _OF _ANNOTATION _CONTEXT             {mkRel(0);}
           | REL_TYPE    _OF _ANNOTATION _CONTEXT IMPLIED_BY  {mkRel(1);}
           | PLAIN_COREF _OF _ANNOTATION _CONTEXT             {mkRelC(0);}
           | PLAIN_COREF _OF _ANNOTATION _CONTEXT IMPLIED_BY  {mkRelC(1);}
           ;
RELATION2  : LTE                                              {mkRelOp("=<");}
           | IMPLIED_BY                                       {mkRelOp("<=");}
           | OTHER_OPERATOR                                   {mkRelOp(fetext);}
           ;

REL_TYPE   : TERM_OR_STR                                      {RelType=Term;}
           ;
PLAIN_COREF: '*'TERM_OR_NUM                                   {Coref="*"+Term;}
           ;

_ANNOTATION:                                                  {Annot[D]="";}
           | ANNOTATION                                       {Annot[D]=fetext;}
           ;
CONCEPT    : CON_CORE _ANNOTATION                             {mkConcept();}
           ;
CON_CORE   : COREF_I  QUANTIFIER RESTRICTOR          _CQ      {mkConCore(1);}
           |          QUANTIFIER RESTRICTOR _COREF_I _CQ      {mkConCore(1);}
           | GROUPOF _QUANTIFIER RESTRICTOR _COREF   _COLL    {mkConCore(2);}
           | GROUPOF _QUANTIFIER            _COREF    COLL    {mkConCore(2);}
           | COREF_I                                 _CQ      {mkConCore(4);}
           |                                          CQ      {mkConCore(5);}
           | NEG_COREF                                        {mkConCore(6);}
           | NUMBER                                   EOT     {mkConCore(7);}
           ;
_CQ        :                   {Cq[D]="";}
           | CQ;
CQ         : COLL              {Cq[D]=Collec[D];ConType[D]="Thing";IsIndiv=1;}
           | Q_SENTENCE        {Cq[D]=FEinCG[D];ConType[D]="Description";}
           ;

NEG_COREF  : '~''*'TERM_OR_NUM             {CorefI[D]="~*"+Term;}
           ;
_COREF_I   :                               {CorefI[D]="";}
           | COREF_I ;
COREF_I    : TERM_OR_STR'\\'CON_TYPE       {IsIndiv=1;CorefI[D]=Term;}
           | TERM_OR_STR                   {IsIndiv=1;CorefI[D]=Term;}
           | NAMED TERM_OR_STR             {IsIndiv=1;CorefI[D]=Term;}
           | '*'TERM_OR_NUM                {CorefI[D]="*"+Term; }
           | '*'TERM_OR_NUM NOT_EQUAL 
                {N1=Term;}'*'TERM_OR_NUM   {CorefI[D]="*"+N1+"!=*"+Term;}
           | '*'TERM_OR_NUM NOT_EQUAL
                {N1=Term;}   TERM_OR_NUM   {CorefI[D]="*"+N1+"!="+Term;}
           ;
_COREF     :                               {CorefI[D]="";}
           | '*'TERM_OR_NUM                {CorefI[D]="*"+Term; }
           | '*'TERM_OR_NUM NOT_EQUAL
                {N1=Term;}'*'TERM_OR_NUM   {CorefI[D]="*"+N1+"!=*"+Term;}
           | '*'TERM_OR_NUM NOT_EQUAL
                {N1=Term;}   TERM_OR_NUM   {CorefI[D]="*"+N1+"!="+Term;}
           ;

RESTRICTOR : _QUALIFIER CON_TYPE           {Restrictor[D]=ConType[D]+Qualifier;}
           | _QUALIFIER '[' CON_TYPE BRANCH_1 _BRANCHES_N ']'
                                           {Restrictor[D]=ConType[D]+Qualifier;}
           ;
CON_TYPE   : TERM_OR_STR                       {ConType[D]=Term;}
           ;
_QUALIFIER :                                   {Qualifier="";}
           | GOOD                              {Qualifier=" @good";}
           | BAD                               {Qualifier=" @bad";}
           | IMPORTANT                         {Qualifier=" @important";}
           | SMALL                             {Qualifier=" @small";}
           | BIG                               {Qualifier=" @big";}
           | GREAT                             {Qualifier=" @great";}
           | CERTAIN                           {Qualifier=" @certain";}
           ;

_QUANTIFIER:                                   {Quantif[D]="";}
           | QUANTIFIER;
QUANTIFIER : EXIST_QUANT                       {Quantif[D]="";}
           | FEW  _OF _THE                     {Qualifier=" @few";}
           | MANY _OF _THE                     {Qualifier=" @many";}
           | EVERY                             {Quantif[D]="any";}
           | ALL                               {Quantif[D]="any";}
           | MOST                     _OF _THE {Quantif[D]="most";}
           | AT_LEAST NUMBER _PERCENT _OF _THE {Quantif[D]="@>="+Num+Perc;}
           | AT_MOST  NUMBER _PERCENT _OF _THE {Quantif[D]="@=<"+Num+Perc;}
           | BETWEEN  NUMBER _PERCENT {N1=Num;}
                  AND NUMBER _PERCENT _OF _THE {Quantif[D]="@"+N1+"|"+Num+Perc;}
           |          NUMBER _PERCENT {N1=Num;}
                   TO NUMBER _PERCENT _OF _THE {Quantif[D]="@"+N1+"|"+Num+Perc;}
           | FROM     NUMBER _PERCENT {N1=Num;}
                   TO NUMBER _PERCENT _OF _THE{Quantif[D]="@"+N1+"->"+Num+Perc;}
           |          NUMBER _PERCENT _OF _THE {Quantif[D]="@"+Num+Perc;}
           |          SEVERAL          OF _THE {Quantif[D]="@severalOf";}
           |          SEVERAL                  {Quantif[D]="@several";}
           |          MOSTLY                   {Quantif[D]="@mostly";}
           |          DOZENS          _OF _THE {Quantif[D]="@dozens";}
           |          HUNDREDS        _OF _THE {Quantif[D]="@hundreds";}
           |          THOUSANDS       _OF _THE {Quantif[D]="@thousands";}
           |          MILLIONS        _OF _THE {Quantif[D]="@millions";}
           |          BILLIONS        _OF _THE {Quantif[D]="@billions";}
           ;
EXIST_QUANT: A | SOME | THE
           ;
GROUPOF    : COREF_I EXIST_QUANT GROUP_TOKEN   {GroupOf[D]=CorefI[D]+
                                                           " "+GroupOf[D];}
           |         EXIST_QUANT GROUP_TOKEN
           | TOGETHER                          {GroupOf[D]="Coll";
                                                Restrictor[D]="Set";}
           ;
GROUP_TOKEN: GROUP_OF          {GroupOf[D]="Coll";Restrictor[D]="Set";}
           | SET_OF            {GroupOf[D]="Coll";Restrictor[D]="Set";}
           | BAG_OF            {GroupOf[D]="Coll";Restrictor[D]="Bag";}
           | SEQUENCE_OF       {GroupOf[D]="Coll";Restrictor[D]="Sequence";}
           | ALTERNATIVE       {GroupOf[D]="Coll";Restrictor[D]="Alternatives";}
           ;
_COLL      : 
           | COLL
           ;
COLL       : '{' {InCollec[++D]=1;}
                 COLL_ELEMS '}' {InCollec[D--]=0;} _COLL_SIZE
           ;
_COLL_SIZE :
           | '@' NUMBER               {Quantif[D]="@"+Num;}
           ;
COLL_ELEMS : ELEM                     {Collec[D-1]="{"+Elem[D]+"}";}
           | ELEM ',' {InCollec[++D]=1;}
                      SET             {--D;Collec[D-1]="{"+Elem[D]+","+Set+"}";}
           | ELEM '&' {InCollec[++D]=1;}
                      BAG             {--D;Collec[D-1]="{"+Elem[D]+"&"+Set+"}";}
           | ELEM '<' {InCollec[++D]=1;}
                      ORDERED_SET     {--D;Collec[D-1]="{"+Elem[D]+"<"+Set+"}";}
           | ELEM LTE {InCollec[++D]=1;}
                      ORDERED_BAG    {--D;Collec[D-1]="{"+Elem[D]+"=<"+Set+"}";}
           | ELEM '/' {InCollec[++D]=1;}
                      XOR_SET         {--D;Collec[D-1]="{"+Elem[D]+"/"+Set+"}";}
           | ELEM '|' {InCollec[++D]=1;}
                      OR_BAG          {--D;Collec[D-1]="{"+Elem[D]+"|"+Set+"}";}
           ;
SET        : ELEM                                    {Set=Elem[D];}
           | ELEM ',' {InCollec[++D]=1;} SET         {Set=Elem[--D]+","+Set;}
           ;
BAG        : ELEM                                    {Set=Elem[D];}
           | ELEM '&' {InCollec[++D]=1;} BAG         {Set=Elem[--D]+","+Set;}
           ;
ORDERED_SET: ELEM                                    {Set=Elem[D];}
           | ELEM '<' {InCollec[++D]=1;} ORDERED_SET {Set=Elem[--D]+"<"+Set;}
           ;
ORDERED_BAG: ELEM                                    {Set=Elem[D];}
           | ELEM LTE {InCollec[++D]=1;} ORDERED_BAG {Set=Elem[--D]+"=<"+Set;}
           ;
XOR_SET    : ELEM                                    {Set=Elem[D];}
           | ELEM '/' {InCollec[++D]=1;} XOR_SET     {Set=Elem[--D]+"/"+Set;}
           ;
OR_BAG     : ELEM                                    {Set=Elem[D];}
           | ELEM '|' {InCollec[++D]=1;} OR_BAG      {Set=Elem[--D]+"|"+Set;}
           ;
ELEM       : CONCEPT                                 {Elem[D]=Concept[D];}
           | '[' TREE ']'                            {Elem[D]=Tree[D];}
           | '*'                                     {Elem[D]="*";}
           ;

TERM_OR_STR: IDENTIFIER                  {ConType[D]="Thing";
                                          upInitial(fetext); delLastS(fetext);
                                          Term=FE_LastToken=fetext;
                                          /*pr("term:%s.\n",fetext);*/}
           | STRING                      {ConType[D]="String";
                                          if (isIdentInString(fetext))
                                          { fetext[strlen(fetext)-1]='\0';
                                            Term=FE_LastToken=(fetext+1);
					  }
                                          else Term=FE_LastToken=fetext;
					 }
           ;
TERM_OR_NUM: IDENTIFIER                  {ConType[D]="Thing";
                                          Term=FE_LastToken=fetext;}
           | NUMERAL                     {ConType[D]="Thing";
                                          Term=FE_LastToken=fetext;}
           ;
NUMBER     : NUMERAL                     {Num=FE_LastToken= fetext;}
           ;
_OF        :                             {Of=0;}
           | OF                          {Of=1;}
           ;
_THE       : | THE;
_PERCENT   :                             {Perc="";}
           | '%'                         {Perc="%";}
           ;

EOT        : '.'                         {unput('.');}
           | '?'                         {unput('?');}
           | ')'                         {unput(')');}
           | ']'                         {unput(']');}
           | '\''                        {unput('\'');/*==yyless(0);*/}
           | ','                      {unput('_');unput(',');unput('_');/*BOB*/}
           | AND                      {unput('_');unput('d');unput('n');
                                                  unput('a');unput('_');/*BOB*/}
           ;
EOS        : '.'                         {IsIt="";             }
           | '?'                         {IsIt="";/*"spec ";*/ }
           ;
%%



void mkFEinCG (int isNegated)
{ if (isNegated) Tree[D]= "~[Description: "+ Tree[D] + "]";
  if (isEmptyS(Branches[D+1])) FEinCG[D]= Tree[D];
  else
  { String br1= popS(Branches[D+1]); String brN, brNs;  IndentS(D+1); //? D+2
    for (brN= popS(Branches[D+1]); !brN.empty(); brN= popS(Branches[D+1]))
    { brNs+= BrIndent+"  "+brN+";\n"; }
    if (brNs.empty()) FEinCG[D]= "[Description: "+Tree[D]+"]"+br1;
    else FEinCG[D]= "[Description: "+Tree[D]+"]-\n"+
                    BrIndent+"{ "+br1+";\n"+ brNs +BrIndent+"}";
  }
#ifndef _IN_WEBKB
 pr("mkFEinCG:%s.\n",FEinCG[D].chars());
#endif
}

void mkTree () /*int withBranches*/
{
/*if (!withBranches)
    Tree[D]= Concept[D]+popS(Branch[D]); //? Concept[D]+popS(Branches[D])
  else*/
    if (InCollec[D] && IsIndiv) Concept[D]= "["+Concept[D]+"]";
    String br1= popS(Branch[D]); if (br1.empty()) br1= popS(Branches[D]);
    String brN; String brNs;     if (br1.empty()) return;   IndentS(D+1);

    if (Relation[D]=="->(Type)->") /* below is an awful hack */
    { if (ConType[D]=="Thing")
        Tree[D]="["+CorefI[D+1]+Concept[D].after("[Thing")+Tree[D+1].after("]");
      else Tree[D]="NSC for "+ConType[D]+"(x) are ["+ConType[D+1]+":*x]"+
                   Tree[D+1].after("]");
#ifndef _IN_WEBKB
 pr("ConType[%d]:%s.\n",D+1,ConType[D+1].chars());
 pr("Relation[%d]:%s.\n",D,Relation[D].chars());
 pr("Tree[%d]:%s.\n",D,Tree[D].chars());
#endif
      return;
    }

    Tree[D]= Concept[D];
    for (brN= popS(Branches[D]); !brN.empty(); brN= popS(Branches[D]))
    { brNs+= BrIndent+"  "+brN+";\n"; }
    if (brNs.empty()) Tree[D]+= br1;
    else Tree[D]+="-\n"+ BrIndent+"{ "+br1+";\n"+ brNs +BrIndent+"}";
    if (InCollec[D]) Tree[D]= "\""+Tree[D]+"\"";
#ifndef _IN_WEBKB
 pr("mkTree(%d,%d):%s.\n",InCollec[D],IsIndiv,Tree[D].chars());
#endif
}


void mkBranch (int isAdef)
{ if (isAdef) { RelType="Type"; Relation[D]="->(Type)->"; }
  else if ((RelType=="Subtype") || (RelType=="Partition"))
  { Concept[D].gsub("[Thing","[Type"); Tree[D+1].gsub("[Thing","[Type"); }
  pushS(Branch[D],Relation[D]+Tree[D+1]);
#ifndef _IN_WEBKB
 pr("mkBranch(%d):%s%s.\n",isAdef,Relation[D].chars(),Tree[D+1].chars());
#endif
}

void mkRel (int isImplication) /*isImplication ignored at present*/
{ if (isUndeclTermEndingByING(RelType))
    Relation[D]= "<-(Agent)<-["+RelType+"]->(Object)->";
  else Relation[D]= (Of)?  "<-("+RelType+")<-"  :  "->("+RelType+")->";
  isImplication=0; /*pr("mkRel:%s\n",Relation[D].chars());*/
}
void mkRelC (int isImplication)
{ Relation[D]= (Of)?  "<-("+Coref+")<-"  :  "->("+Coref+")->";
  isImplication=0;
}
void mkRelOp (char *oper) /*  =>  <=>  <=   =  !=  <  =<  >  >=  ?  */
{ switch (oper[0])
  { case '!': Relation[D]= "->(Different_from)->"; break;
    case '=': switch (oper[1])
              { case '>': Relation[D]= "->(Implication)->"; break;
                case '<': Relation[D]= "->(LTE)->"; break;
                case '\0': Relation[D]= "->(Equal)->"; break;
	      } break;
    case '<': switch (oper[1])
              { case '=': if (!oper[2]) Relation[D]= "<-(Implication)<-";
                          else Relation[D]= "->(Equivalence)->";
                          break;
                case '\0': Relation[D]= "->(LT)->"; break;
	      } break;
    case '>': switch (oper[1])
              { case '=': Relation[D]= "<-(LTE)<-"; break;
                case '\0': Relation[D]= "<-(LT)<-"; break;
	      } break;
    case '?': Relation[D]= "->(Relation)->"; break;
  }
}

void mkConcept ()
{ if (InCollec[D] && IsIndiv/*&&!withBranches*/) Concept[D]=ConCore[D]+Annot[D];
  else 
  { if (Annot[D].empty()) Concept[D]= "["+ConCore[D]+"]";
    else Concept[D]= "["+ConCore[D]+" "+Annot[D]+"]";
  }
  IsIndiv=0; if (WithTrace) pr("----> Concept[%d]:%s. \n",D,Concept[D].chars());
  /* unput(' '); unput('@'); unput('@'); unput(' '); EOC (End of Concept)*/
}

void mkConCore (int conCoreCase)
{ if (WithTrace)
    pr("conCoreCase:%d, %d:%d-%d, Restrictor:%s, Quantif:%s.%s, Cq:%s.\n",
        conCoreCase,D,InCollec[D],IsIndiv,Restrictor[D].chars(),
        Quantif[D].chars(),Qualifier.chars(),Cq[D].chars());

  //first, move the Quantif[D]=="@..." into Collec[D] or Cq[D]
  //if Quantif.length() not tested before accessing Quantif[0], no more output
  if ((conCoreCase<=3) && Quantif[D].length() && (Quantif[D][0]=='@'))
  { if (conCoreCase==1) Cq[D]+=Quantif[D]; else Collec[D]+=Quantif[D];
    Quantif[D]="";
  } 
  switch (conCoreCase)
  { case 1: if (CorefI[D].length()) CorefI[D]=" "+CorefI[D];
            if (Cq[D].length()) Cq[D]=" "+Cq[D];
            if (Quantif[D].length()) Quantif[D]=" "+Quantif[D];
            ConCore[D]= Quantif[D]+CorefI[D]+Cq[D];
            if (ConCore[D].length()) ConCore[D]=Restrictor[D]+":"+ConCore[D];
            else ConCore[D]= Restrictor[D];
            break;
    case 2: if (CorefI[D].length()) CorefI[D]=" "+CorefI[D];
            ConCore[D]=Restrictor[D]+": "+GroupOf[D]+CorefI[D]+" "+Collec[D];
            break;
    case 4: if (Cq[D].length()) Cq[D]=" "+Cq[D];
            if (InCollec[D]) ConCore[D]= CorefI[D]+Cq[D];
            else if (!CorefI[D].length()) ConCore[D]= ConType[D]+":"+Cq[D];
                 else ConCore[D]= ConType[D]+": "+CorefI[D]+Cq[D];
            break;
    case 5: if (InCollec[D]/*||(ConType[D]=="Description")*/) ConCore[D]=Cq[D];
            else ConCore[D]=ConType[D]+": "+Cq[D];
            break;
    case 6: ConCore[D]= CorefI[D]; break;
    case 7: ConCore[D]= "Number: "+Num; break;
  }
}

int isIdentInString (char *s)
{ char c= *(s+1); if (!(isalpha(c)||(c=='#'))) return 0;
  for ( ; *s; s++) { if (isspace(*s)||(*s=='*')) return 0; }
  return 1;
}




static int strEq (char *a, char *b)
{ for(;*a && *b; a++,b++) { if (*a != *b) return 0; }
  if (*a || *b) return 0;  return 1;
}
int isFormalisedEnglish (char *arg0, char *arg1)
{ int c;
  if (isupper(arg0[0]))
  { if (arg1[0]=='(') return 0; //relation declaration
    switch ((c= arg1[0])) //is/has/the
    { case 'i': if ((arg1[1]=='s') && !arg1[2]) return 1;  break;
      case 'h': if (strEq(arg1+1,"as")) return 1;  break;
      case 't': if (strEq(arg1+1,"he"))  return 1;
    }
  }
  else if (isdigit(arg0[0])) return 1;

  switch ((c= tolower(arg0[0])))
  { case 'a': switch ((c= arg0[1]))
              { case '\0': return 1; /*a*/
                case 'n': c=arg0[2]; if (!c) return 1; /*an*/
                          if ((c=='y') && !arg0[3]) return 1;  /*any*/ break;
                case 'r': if (strEq(arg0+1,"re")) return 1; /*are*/
                case 't': if (!arg0[2]) return 1; /*at*/
              }break;
    case 'b': if (strEq(arg0+1,"etween")||strEq(arg0+1,"illions")) return 1;
              break;
    case 'd': if (arg0[1]=='o') /*do/does/dozen*/ 
                if (!arg0[2]||strEq(arg0+2,"es")||strEq(arg0+2,"zen")) return 1;
              break;
    case 'e': if (strEq(arg0+1,"very")) return 1; /*every*/ 
              break;
    case 'f': if (strEq(arg0+1,"ew")||strEq(arg0+1,"rom")) return 1;/*few/from*/
              break;
    case 'h': if (strEq(arg0+1,"undreds")) return 1; /*hundreds*/
              break;
    case 'i': c=arg0[1]; if ((c=='s') && !arg0[2]) return 1; /*is (there ...)*/
              break;
    case 'm': switch ((c= arg0[1])) /*many/most(ly)/millions*/
              { case 'a': if (strEq(arg0+2,"ny"))return 1;
                case 'o': if (strEq(arg0+2,"st")||strEq(arg0+2,"stly"))return 1;
                case 'i': if (strEq(arg0+2,"illions")) return 1;
              }break;
    case 's': if (strEq(arg0+1,"ome")||strEq(arg0+1,"everal")) return 1; break;
    case 't': if (strEq(arg0+1,"he")||strEq(arg0+1,"ogether")) return 1; break;
    case '*': return 1;  /*reference*/                  
    case '`': return 1;  /*quoted sentence*/                  
    case '{': return 1;  /*set*/                  
  }
  return 0;
}





int fewrap() { return 1; }

int feerror(const char *s)
{ int l=strlen(ParsingError); ParsingError[l]='\n';
  if (FE_LastToken.empty())
    sprintf(ParsingError+l+1,"at \"%s\": %s.\n",fetext,s);
  else sprintf(ParsingError+l+1,"after \"%s\", at \"%s\": %s.\n",
                                FE_LastToken.chars(),fetext,s);
#ifndef _IN_WEBKB
  printf(ParsingError);
#endif
  return 1;
}

char *formalisedEnglishToCGs (char *fe)
{ int i; if (!fe) return NULL;  if (WithTrace) printf("fe:%s.\n",fe);
  yy_scan_string(fe);
  for (i=0;i<MAX_DEPTH;i++)
  { InCollec[i]=0; Branch[i]=newS(); Branches[i]=newS(); }
  errno=0; ParsingError[0]='\0'; FE_LastToken="";   feparse();
  for (i=0;i<MAX_DEPTH;i++) { delS(Branch[i]); delS(Branches[i]); }
  return (char *) FEinCGs.chars();
}
/* Example:
A cat is watching a mouse and is on a table, on a mat and near a box.
Many cats are watching a mouse on a table which is on a mat near a box. 
spec [Thing]
*/



/* Management of stacks of strings */
StringList *newS ()
{ StringList *newList= new StringList; 
  if (newList) {newList->object=""; newList->next=NULL;}   return newList;
}
void delS (StringList *me)
{ StringList *current;  if (!me) return; 
  while ((current=me)) { me= me->next; delete current; }
}
void pushS (StringList *me, String str)
{ StringList *newNode= new StringList;
  if (newNode) {newNode->object=str; newNode->next=me->next; me->next=newNode;}
  else feerror("Cannot store a new string");
}
String popS (StringList *me)
{ if (me && me->next)
  { StringList *lastNode=me->next;  String lastObject=lastNode->object;
    me->next=lastNode->next;  delete lastNode; return lastObject;
  }
  else  return String("");  /* Empty list */
}
int isEmptyS (StringList *me)
{ if (!me) return 1;  return (me->next == NULL);
}

void upInitial (/*varP*/char *str)
{ str[0]=toupper(str[0]); }

void delLastS (/*varP*/char *str)
{ int l=strlen(str); if (l<3) return;
  if ((str[l-1]=='s') && (str[l-2]!='s') && (str[l-2]!='i')) str[l-1]='\0';
}


#ifndef _IN_WEBKB
int main()
{ char line[200]; printf("> ");  if (WithTrace) yydebug=1;
  while (fgets(line,200,stdin))
  { puts(formalisedEnglishToCGs(line)); printf("> "); }
  puts("\n");
}
#endif
