view anagram/agcore/ut.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children 5b21f127e957
line wrap: on
line source

/*
 * AnaGram, A System for Syntax Directed Programming
 * Copyright 1993-2002 Parsifal Software. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * ut.cpp
 */

#include <stdio.h>
#include "port.h"

#include "csexp.h"
#include "dict.h"
#include "keyword.h"
#include "q1glbl.h"
#include "rule.h"
#include "stacks.h"
#include "symbol.h"
#include "token.h"
#include "tree.h"
#include "ut.h"

//#define INCLUDE_LOGGING
#include "log.h"


#define PUREMARK '%'



void append_ascii_char(unsigned int j) {
  switch (j) {
    case '\a':
      ass("\\a");
      break;
    case '\b':
      ass("\\b");
      break;
    case '\f':
      ass("\\f");
      break;
    case '\n':
      ass("\\n");
      break;
    case '\r':
      ass("\\r");
      break;
    case '\t':
      ass("\\t");
      break;
    case '\v':
      ass("\\v");
      break;
    case '\'':
    case '\\':
    case '\"':
      apprintf("\\%c",j);
      break;
    default:
      if (j >= 32 && j < 127) {
	acs(j);
      }
      else {
	apprintf("\\%o",j);
      }
      break;
  }
}

void append_char_range(int i, int j) {
  const char *fmt;
  if (i == j) {
    append_char_rep(i);
    return;
  }
  if (j <= 32 || i >= 127) {
    fmt = "%d..%d";
  }
  else if (i > 32 && j < 127) {
    fmt = "'%c-%c'";
  }
  else if (i > 32) {
    fmt = "'%c'..%d";
  }
  else if (j < 127) {
    fmt = "%d..'%c'";
  }
  else {
    fmt = "%d..%d";
  }
  apprintf(fmt, i,j);
}

void append_char_rep(int j) {
  switch (j) {
    case '\a':
      ass("'\\a'");
      break;
    case '\b':
      ass("'\\b'");
      break;
    case '\f':
      ass("'\\f'");
      break;
    case '\n':
      ass("'\\n'");
      break;
    case '\r':
      ass("'\\r'");
      break;
    case '\t':
      ass("'\\t'");
      break;
    case '\v':
      ass("'\\v'");
      break;
    case '\'':
    case '\\':
    case '\"':
      apprintf("'\\%c'", j);
      break;
    default:
      if (j > 0 && j <= 26) {
	apprintf("^%c", j+64);
      }
      else if (j >=32 && j < 127) {
	apprintf("'%c'", j);
      }
      else {
	apprintf("%d", j);
      }
  }
}

void append_string_char(int j) {
  switch (j) {
    case '\a':
      ass("\\a");
      break;
    case '\b':
      ass("\\b");
      break;
    case '\f':
      ass("\\f");
      break;
    case '\n':
      ass("\\n");
      break;
    case '\r':
      ass("\\r");
      break;
    case '\t':
      ass("\\t");
      break;
    case '\v':
      ass("\\v");
      break;
    case '\\':
    case '\"':
      apprintf("\\%c",j);
      break;
    default:
      if (j >= 32 && j < 127) {
	acs(j);
      }
      else {
	apprintf("\\%o",j);
      }
      break;
  }
}

static void append_vp_form(VpRule vpRule) {
  int n, i;
  AgArray<RuleElement> elementList = vpRule->elementList;
  n = elementList.size();
  const char *cs = "";
  for (i = 0; i < n; i++) {
    ass(cs);
    atkn(elementList[i].token);
    cs = ", ";
  }
}

static void append_vp_forms(int *lb, int n) {
  const char *cs;
  int i;

  cs = "";
  for (i = 0; i < n; i++) {
    ass(cs);
    append_vp_form(*lb++);
    cs = " | ";
  }
}

AgString proc_name_string(int pn) {
  LOGSECTION("proc_name_string");
  LOGV(pn);
  char buf[100];
  sprintf(buf, "ag_rp_%d", pn);
  LOGV(buf);
  return AgString(buf);
}

void avptkn(int tn) {
  int vpt, *lb, n, pn;

  lb = dict_str(vp_prod_dict,tn);
  n = *lb++ - 1;
  vpt = lb[--n];
  switch (vpt) {
    case 1:        /* {forms} */
      acs('{');
      append_vp_forms(lb,n);
      acs('}');
      break;
    case 2:        /* {forms}... */
      acs('{');
      append_vp_forms(lb,n);
      ass("}...");
      break;
    case 3:        /* [forms] */
      acs('[');
      append_vp_forms(lb,n);
      acs(']');
      break;
    case 4:        /* [forms]... */
      acs('[');
      append_vp_forms(lb,n);
      ass("]...");
      break;
    case 5:        /* name? */
      atkn(*lb);
      acs('?');
      break;
    case 6:        /* name?... */
      atkn(*lb);
      ass("?...");
      break;
    case 7:        /* name... */
      atkn(*lb);
      ass("...");
      break;
    case 8:        /* !proc */
      acs('!');
      pn = Rule(*lb)->proc_name;
      ass(proc_name_string(pn).pointer());
      break;
  }
}

void atkn(Token token) {
  Keyword key;
  int pn;
  int vptn;

  LOGSECTION("atkn");
  LOGV(token);

  //Does token have an explicit name, if so, use that.
  Symbol tokenName = token->token_name;
  if (tokenName.isNotNull()) {
    LOGV(tokenName) LCV(tokenName->string.pointer());
    ass(tokenName->string.pointer());
    if (token->pure) acs(PUREMARK); return;
  }
  // token does not have an explicit name. Is it a keyword?
  LOGV(token);
  key = token->key;
  //if (key) {
  if (key.isNotNull()) {
    acs('"');
    append_key(key);
    acs('"');
    if (token->pure) acs(PUREMARK);
    return;
  }

  // token isn't a keyword. Does it have a parse tree?
  LOGV(token);
  LOGV(token->parse_tree) LCV(ParseTree::count());
  ParseTree tokenParseTree = token->parse_tree;
  LOGV(tokenParseTree);
  LOGV(token);
  if (tokenParseTree.isNotNull()) {
    Symbol parseTreeName = tokenParseTree->token_name;
    LOGV(parseTreeName);
    if (parseTreeName.isNotNull() && parseTreeName->token_number == token) {
      LOGV(tokenParseTree) LCV(parseTreeName->string.pointer());
      tokenName = parseTreeName;
      ass(tokenName->string.pointer());
      if (token->pure) acs(PUREMARK);
      return;
    }
    // Parse tree has no name, so use the expression
    LOGV(token);
    LOGV(tokenParseTree->expression->asString().pointer());
    ass(tokenParseTree->expression->asString().pointer());
    if (token->pure) acs(PUREMARK);
    return;
  }
  // No parse tree. Try virtual production
  LOGV(token);
  LOGV(token->vp_prod_number);
  if ((vptn = token->vp_prod_number) != 0){
    LOGV(vptn);
    avptkn(vptn);
    if (token->pure) acs(PUREMARK);
    return;
  }
  // No virtual production. Is this a partition token?
  LOGV(token);
  LOGV(token->part_number);
  if ((pn = token->part_number) != 0) {
    LOGV(pn);
    apprintf("P%03d", pn);
    if (token->pure) acs(PUREMARK);
    return;
  }
  // Try for immediate action
  LOGV(token);
  //LOGV(token->n_expansion_forms);
  //if (token->n_expansion_forms == 1) {
  if (token->expansionRuleList.size() == 1) {
    //unsigned *fl = lstptr(*tp, expansion_forms);
    //unsigned *fl = token->expansion_forms();
    LOGV(token);
    LOGV(token.expansionRule(0));
    Rule rule = token.expansionRule(0);
    LOGV(rule);
    if (rule->immediate_proc) {
      apprintf("!ag_rp_%d", rule->proc_name);
      if (token->pure) acs(PUREMARK);
      return;
    }
  }
  // none of those things. Be satisfied with token number
  apprintf("T%03d",(int) token);
  if (token->pure) acs(PUREMARK);
}

AgString token_string(unsigned tn) {
  ics();
  atkn(tn);
  return buildAgString();
}

static void append_item_only(int f, int x) {
  int n, i;
  const char *cs;

  Rule rule = f;
  n = rule->length();
  cs = "";
  for (i = 0; i < n; i++) {
    ass(cs);
    if (i == x) {
      ass("< ");
    }
    atkn(rule.token(i));
    //if (i == x) {
    //  acs('þ');
    //}
    if (i == x) {
      acs('>');
    }
    cs = ", ";
  }
  if (i == x) {
    if (i > 0) {
      acs(' ');
    }
#ifdef OLDUI
    acs('þ');
#endif
  }
}

void append_item(int f, int x) {
  if (nforms < 1000) {
    apprintf("R%03d:  ", f);
  }
  else {
    apprintf("R%04d: ", f);
  }
  append_item_only(f, x);
}

void append_item_brkt(int f, int brkt) {
  int n, i;
  const char *cs;

  Rule rule = f;
  n = rule->length();
  if (nforms < 1000) {
    apprintf("R%03d:  ", f);
  }
  else {
    apprintf("R%04d: ", f);
  }
  cs = "";
  for (i = 0; i < n; i++) {
    ass(cs);
    if (i == brkt) {
      ass("< ");
    }
    atkn(rule.token(i));
    if (i == brkt) {
      acs('>');
    }
    cs = ", ";
  }
}