view anagram/agcore/ut.cpp @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -0400
parents 5b21f127e957
children
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 = ", ";
  }
}