/*-----------------------------------------------------------------
Printy.atg
2005-06 Philipp Grasboeck
-------------------------------------------------------------------*/

COMPILER Printy

  public Grammar grammar;

CHARACTERS
  letter     = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
  digit      = "0123456789".
  tab        = '\t'.
  cr         = '\r'.
  lf         = '\n'.
  eol        = cr + lf.
  stringCh   = ANY - '"' - '\\' - eol.
  charCh     = ANY - '\'' - '\\' - eol.
  printable  = '\u0020' .. '\u007e'.
  hex        = "0123456789abcdef".
  pCommentCh = ANY - "*)".
  cCommentCh = ANY - "*/".
  lCommentCh = ANY - eol.

TOKENS
  ident  = letter { letter | digit }.
  string = '"' { stringCh | '\\' printable } '"'.
  char   = '\'' ( charCh | '\\' printable { hex } ) '\''.

PRAGMAS
  cComment = "/*" { '/' | cCommentCh | '*' {'*'} cCommentCh } '*' {'*'} '/'.  (. RegisterComment(t,la); .)
  pComment = "(*" { ')' | pCommentCh | '*' {'*'} pCommentCh } '*' {'*'} ')'.  (. RegisterComment(t,la); .)
  lComment = "//" { lCommentCh } eol.                                         (. RegisterComment(t,la); .)
  ddtSym   = '$' { digit | letter }.

IGNORE eol + tab

/*------------------------------------------------------------------------------------*/

PRODUCTIONS

Printy                            (. Node n, curr = null; .)
=
  { ANY }
  "COMPILER" ident                (. grammar = new Grammar(t.val); .)
  { ANY }
  "PRODUCTIONS"                   (. grammar.meta = new Node(Node.Log,scanner.buffer.GetString(0,la.pos),null,la);
                                     RegisterLines(la.line - 1);
                                   .)
  Production<out grammar.sub>
  { Production<out n>             (. n.Enqueue(grammar.sub,ref curr); .)
  }
  "END"                           (. Token start = t; .)
  ident
  '.'                             (. grammar.meta.next = new Node(Node.Log,scanner.buffer.GetString(start.pos,la.pos),start,la);
                                     RegisterLines(la.line - start.line);
                                   .)
.

/*------------------------------------------------------------------------------------*/

Production<out Node node>         (. Node n; .)
=
  ident                           (. grammar.nts[t.val] = node = new Node(Node.Production,t); .)
  [ Attribute<out node.meta> ]
  [ Action<out n>                 (. if (node.meta == null) node.meta = n; else node.meta.next = n; .)
  ]
  WEAK '='                        (. node.open = t; .)
  Expression<out node.sub>
  WEAK '.'                        (. node.close = t; .)
.

/*------------------------------------------------------------------------------------*/

Expression<out Node node>         (. Node n, curr = null; .)
=
  Term<out node>
  { WEAK '|'                      (. Token sep = t; .)
    Term<out n>                   (. n.EnqueueAlt(node,ref curr); n.sep = sep; .)
  }
.

/*------------------------------------------------------------------------------------*/

Term<out Node node>               (. Node n, curr = null; .)
=                                 (. node = null; .)
  ( [ Resolver<out node> ]
    Factor<out n>                 (. if (node == null) node = n; else n.Enqueue(node,ref curr); .)
    { Factor<out n>               (. n.Enqueue(node,ref curr); .)
    }
  |                               (. node = new Node(Node.Epsilon); .)
  )                               (. if (node == null) node = new Node(Node.Epsilon); .)
.

/*------------------------------------------------------------------------------------*/

Factor<out Node node>
=                                 (. node = null; .)
  ( Symbol<out node>
  | Literal<out node>
  | Action<out node>
  | '('                           (. node = new Node(Node.Group); node.open = t; .)
    Expression<out node.sub>
    ')'                           (. node.close = t;  .)
  | '['                           (. node = new Node(Node.Group); node.open = t; .)
    Expression<out node.sub>
    ']'                           (. node.close = t;  .)
  | '{'                           (. node = new Node(Node.Group); node.open = t; .)
    Expression<out node.sub>
    '}'                           (. node.close = t;  .)
  )                               (. if (node == null) node = new Node(Node.Epsilon); .)
.

/*------------------------------------------------------------------------------------*/

Symbol<out Node node>
=                                 (. node = new Node(Node.Symbol,la); .)
  ident
  [ Attribute<out node.meta> ]
.

/*------------------------------------------------------------------------------------*/

Literal<out Node node>
=                                 (. node = new Node(Node.Literal,la); .)
  ( string | char
  | "WEAK" | "SYNC" | "ANY"
  )
.

/*------------------------------------------------------------------------------------*/

Resolver<out Node node>           (. Token start = la; .)
=
  "IF" '('
  Condition                       (. node = new Node(Node.Resolver,scanner.buffer.GetString(start.pos,t.pos + 1),start,t);
                                     RegisterLines(t.line - start.line);
                                   .)
.

/*------------------------------------------------------------------------------------*/

Condition
=
  { '(' Condition
  | ANY
  } ')'
.

/*------------------------------------------------------------------------------------*/

Attribute<out Node node>          (. Token start = la; .)
=
  '<'
  { ANY }
  '>'                             (. node = new Node(Node.Attribute,scanner.buffer.GetString(start.pos,t.pos + 1),start,t);
                                     RegisterLines(t.line - start.line);
                                   .)
.

/*------------------------------------------------------------------------------------*/

Action<out Node node>             (. Token start = la; .)
=
  "(."
  { ANY }
  ".)"                            (. node = new Node(Node.Action,scanner.buffer.GetString(start.pos,t.pos + 2),start,t);
                                     RegisterLines(t.line - start.line);
                                   .)
.

/*------------------------------------------------------------------------------------*/

END Printy.