view anagram/agcore/bpu.cpp @ 8:ec2b657edf13

Add explicit lint-comment-style fallthrough annotations. GCC now assumes that if you don't have these you're making a mistake, which is annoying. XXX: This changeset updates the AG output files only (by hand) and is XXX: abusive - rebuilding them will erase the change. However, I need XXX: to get things to build before I can try to get AG to issue the XXX: annotations itself, so this seems like a reasonable expedient.
author David A. Holland
date Mon, 30 May 2022 23:51:43 -0400
parents 13d2b8934445
children
line wrap: on
line source

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

#include <ctype.h>
#include <stdarg.h>
#include "port.h"

#include "arrays.h"
#include "bpe3.h"
#include "bpu.h"
#include "cd.h"
#include "data.h"
#include "dict.h"
#include "engdef.h"
#include "keyword.h"
#include "myalloc.h"
#include "q1glbl.h"
#include "rule.h"
#include "stacks.h"
#include "symbol.h"
#include "token.h"

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


void template_string(const char *name, const char *tp, const char tc) {
  ics();
  while (*tp) {
    char c = *tp++;
    if (c == tc) {
      ass(name);
      continue;
    }
    acs(c);
  }
  tss();
}

AgString subs_template(const char *name, const char *tp, const char tc) {
  template_string(name, tp, tc);
  return buildAgString();
}

unsigned find_token_number(const char *name) {
  return Symbol(name)->token_number;
  //return map_token_name[identify_string(name,tkn_dict)].token_number;
}

int find_completions(int s, const unsigned **q) {
  state_number_map *sp = &map_state_number[s];
  const unsigned *p = lstptr(*sp, chain_completions);
  int n = sp->n_chain_completions;
  if (n == 0 && sp->chain_gotos_index == 0) {
    p = lstptr(*sp, completions);
    n = sp->n_completions;
  }
  *q = p;
  return n;
}

void select_actions(int k) {
  int n = tis()/3;
  int *lb;

  list_space(n+1);
  lb = list_base;
  iws();
  while (n--) {
    aws(lb[k]);
    k += 3;
  }
}

void find_key_tokens(const int *pl, int n, int tw /*, int ct */) {
  LOGSECTION("find_key_tokens");
  LOGV(n);
  for (; n--; pl += tw) {
    //int tn = *pl;
    Token token = *pl;
    LOGV(token);
    //if (map_token_number[tn].key == 0) continue;
    //if (token->key == 0) continue;
    if (token->key.isNull()) {
      continue;
    }
    isws(token);
  }
}


/*
 * Note that the text of the defined format must not contain a newline.
 * Failure to abide by this rule will cause the line count to be
 * incorrect.
 */

void define_macro(const char *n, const char *fmt, ...) {
  va_list ap;
  fprintf(pe_file, "#define %s ", n);
  va_start(ap, fmt);
  vfprintf(pe_file, fmt, ap);
  va_end(ap);
  fputc('\n', pe_file);
  pe_line_count++;
}

void define_macro_default(const char *n, const char *fmt, ...) {
  va_list ap;
  char name_only[80];
  char *ptr;

  strcpy(name_only, n);
  ptr = strchr(name_only, '(');

  if (ptr != NULL) {
    *ptr = 0;
  }

  fprintf(pe_file, "#ifndef %s\n#define %s ", name_only, n);
  va_start(ap, fmt);
  vfprintf(pe_file, fmt, ap);
  va_end(ap);
  fprintf(pe_file, "\n#endif\n");
  pe_line_count += 3;
}

unsigned char *key_string(int tn) {
  LOGSECTION("key_string");
  Keyword key = map_token_number[tn].key;
  LOGV(tn) LCV(key) LCV(Keyword::count());

  if (key.isNull()) {
    return NULL;
  }
  LOGV(key->string);
  return (unsigned char *) key->string.pointer();
}

/*
 * Function:  reducing_token
 * Arguments:
 *   token number, tn
 *   state number, sn
 * Returns: 0 if tn is _not_ a reducing token in the given state
 * Otherwise, returns the number of the rule it reduces.
 */

#if 0 /* no longer used */
unsigned reducing_token(unsigned tn, unsigned sn) {
  state_number_map *sp = &map_state_number[sn];
  const unsigned *p;
  unsigned n = sp->n_reductions;     /* number of reductions in this state */

  if (n) {
    p = lstptr(*sp, reductions);
    while (n--) {
      if (*p++ == tn) {
        return *p;
      }
      p++;
    }
    return 0;
  }
  if (sp->n_completed_forms != 1) {
    return 0;
  }
  if (shift_token(tn, sn)) {
    return 0;
  }
  return *(lstptr(*sp,completed_forms));
}
#endif /* 0 - no longer used */

Rule ruleReducedBy(Token token, unsigned sn) {
  state_number_map *sp = &map_state_number[sn];
  const unsigned *p;
  unsigned n = sp->n_reductions;     /* number of reductions in this state */

  if (n) {
    p = lstptr(*sp, reductions);
    while (n--) {
      if (*p++ == (unsigned) token) {
        return *p;
      }
      p++;
    }
    return 0;
  }
  if (sp->n_completed_forms != 1) {
    // Exit if more than one completed rule
    return 0;
  }
  if (shift_token(token, sn)) {
    // Exit if there's a shift
    return 0;
  }
  // Default reduction, return rule #
  return *(lstptr(*sp, completed_forms));
}

void select_write_fragment(const char *name, const char *modes,
			   const char *suffix) {
  char fragment[80];

  strcpy(fragment, name);
  strcat(fragment, modes);
  strcat(fragment, suffix);
  write_code_segment(fragment);
}

int shift_token(unsigned tn, unsigned sn) {
  const unsigned *p;
  unsigned n;

  n = find_gotos(sn, &p);
  while (n--) {
    if (*p == tn) {
      return 1; 
    }
    else {
      p += 2;
    }
  }

  n = find_completions(sn, &p);
  while (n--) {
    if (*p == tn) {
      return 1;
    }
    else {
      p += 2;
    }
  }

  return 0;
}

void count_pe_line(const char *s, int k) {
  LOGSECTION("count_pe_line");

  while (k--) {
    if (s[k] == '\n') {
      pe_line_count++;
    }
  }
  LOGV(pe_line_count);
}

int wps(const char *s) {
  LOGSECTION("wps");
  int k = strlen(s);

  fputs(s, pe_file);
  count_pe_line(s, k);
  return k;
}

int wss(void) {
  count_pe_line(string_base, tis());
  fputs(string_base, pe_file);
  return rcs();
}

int wpe(const char *fs, ...) {
  LOGSECTION("wpe");
  va_list ap;
  char buf[2000];

  va_start(ap, fs);
  vsprintf(buf, fs, ap);
  va_end(ap);
  return wps(buf);
}

void write_code_segment(const char *name) {
  LOGSECTION("write_code_segment");
  LOGV(name);
  if (name == NULL) {
    return;
  }
  AgString text = code_segment(name);
  if (!text.exists()) {
    return;
  }
  char *buf = text.pointer();
  wps(buf);
  wps("\n\n");
}

static AgString expand_my_macros(const char *s) {
  LOGSECTION("expand_my_macros");
  char *p;
  int col_no = 0, lb = 0, k;

  LOGV(s);
  if (my_macros == NULL) {
    return AgString(s);
  }
  ics();
  while (*s) {
    char *word;
    int index;

    while (*s && !isalpha(*s) && *s != '_') {
      if (*s == '\n') {
        acs(*s++);
        col_no = 0;
        while (*s && *s == ' ') {
	  col_no++, s++;
	}
        lb = col_no;
        continue;
      }
      if (lb == col_no) {
	for (k = lb; k--; ) {
	  acs(' ');
	}
      }
      col_no++;
      acs(*s++);
    }
    if (*s == 0) {
      break;
    }
    ics();
    while (*s && (isalpha(*s) || *s == '_')) {
      acs(*s++);
    }
    word = build_string();
    index = identify_string(word, my_macros);
    if (index == 0) {
      if (lb == col_no) {
	for (k = lb; k--; ) {
	  acs(' ');
	}
      }
      col_no += strlen(word);
      ass(word);
      DEALLOCATE(word);
      continue;
    }
    DEALLOCATE(word);
    p = my_macros_subs[index];
    if (*p == 0 && lb == col_no && (*s == '\n' || strncmp(s,"\\\n",2) == 0)) {
      if (*s == '\\') {
	s++;
      }
      s++;
      col_no = 0;
      while (*s && *s == ' ') {
	col_no++;
	s++;
      }
      lb = col_no;
      continue;
    }
    if (lb == col_no) for (k = lb; k--;) acs(' ');
    for (; *p; p++ ) {
      acs(*p);
      col_no++;
      if (*p == '\n') {
        for (k = lb; k--; ) {
	  acs(' ');
	}
        col_no = lb;
        continue;
      }
    }
    if (*s == '#') {
      s++;
    }
  }
  LOGV(string_base);
  return buildAgString();
}


AgString code_segment(const char *name) {
  LOGSECTION("code_segment");

  const char *rawtext = engdef_get(name);
  LOGV(rawtext);

  AgString mx = expand_my_macros(rawtext);
  LOGV(mx);

  return mx;
}