about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--subx/033non_code_segment.cc30
-rw-r--r--subx/034discourage_raw_hex.cc36
-rw-r--r--subx/035labels.cc4
-rw-r--r--subx/036recommend_labels.cc81
-rw-r--r--subx/037label_types.cc45
-rw-r--r--subx/038check_local_jumps.cc60
-rw-r--r--subx/subx.vim17
7 files changed, 4 insertions, 269 deletions
diff --git a/subx/033non_code_segment.cc b/subx/033non_code_segment.cc
deleted file mode 100644
index c0549023..00000000
--- a/subx/033non_code_segment.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-//: Raise an error when operand metadata is used in non-code segments.
-
-:(scenario operand_metadata_outside_code_segment)
-% Hide_errors = true;
-== 0x1  # code segment
-cd 0x80/imm8
-== 0x1000  # data segment
-cd 12/imm8
-+error: 12/imm8: metadata imm8 is only allowed in the (first) code segment
-
-:(before "Pack Operands(segment code)")
-ensure_operands_only_in_code_segments(p);
-if (trace_contains_errors()) return;
-:(code)
-void ensure_operands_only_in_code_segments(const program& p) {
-  trace(99, "transform") << "-- ensure operands only in code segments" << end();
-  if (p.segments.empty()) return;
-  for (int i = /*skip code segment*/1;  i < SIZE(p.segments);  ++i) {
-    const segment& seg = p.segments.at(i);
-    for (int j = 0;  j < SIZE(seg.lines);  ++j) {
-      const line& l = seg.lines.at(j);
-      for (int k = 0;  k < SIZE(l.words);  ++k) {
-        const word& w = l.words.at(k);
-        for (map<string, uint32_t>::iterator p = Operand_bound.begin();  p != Operand_bound.end();  ++p)
-          if (has_metadata(w, p->first))
-            raise << w.original << ": metadata " << p->first << " is only allowed in the (first) code segment\n" << end();
-      }
-    }
-  }
-}
diff --git a/subx/034discourage_raw_hex.cc b/subx/034discourage_raw_hex.cc
deleted file mode 100644
index 2b2e2675..00000000
--- a/subx/034discourage_raw_hex.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-//: Now that we have operand metadata, start warning on instructions that
-//: don't use it.
-//:
-//: While SubX will let you write raw machine code, don't do that unless you
-//: have a very good reason.
-
-:(before "Pack Operands(segment code)")
-warn_on_raw_hex(code);
-if (trace_contains_errors()) return;
-:(code)
-void warn_on_raw_hex(const segment& code) {
-  trace(99, "transform") << "-- warn on raw hex instructions" << end();
-  for (int i = 0;  i < SIZE(code.lines);  ++i) {
-    const line& inst = code.lines.at(i);
-    if (all_hex_bytes(inst) && has_operands(inst)) {
-      warn << "'" << to_string(inst) << "': using raw hex is not recommended\n" << end();
-      break;
-    }
-  }
-}
-
-:(scenarios transform)
-:(scenario warn_on_hex_bytes_without_operands)
-== 0x1
-bb 2a 00 00 00  # copy 0x2a (42) to EBX
-+warn: 'bb 2a 00 00 00': using raw hex is not recommended
-
-:(scenario warn_on_non_operand_metadata)
-== 0x1
-bb 2a 00/foo 00/bar 00  # copy 0x2a (42) to EBX
-+warn: 'bb 2a 00/foo 00/bar 00': using raw hex is not recommended
-
-:(scenario no_warn_on_instructions_without_operands)
-== 0x1
-55  # push EBP
--warn: '55': using raw hex is not recommended
diff --git a/subx/035labels.cc b/subx/035labels.cc
index 236c8fa2..0d366d2e 100644
--- a/subx/035labels.cc
+++ b/subx/035labels.cc
@@ -1,5 +1,9 @@
 //: Labels are defined by ending names with a ':'. This layer will compute
 //: addresses for labels, and compute the offset for instructions using them.
+//:
+//: We won't check this, but our convention will be that jump targets will
+//: start with a '$', while functions will not. Function names will never be
+//: jumped to, and jump targets will never be called.
 
 //: We're introducing non-number names for the first time, so it's worth
 //: laying down some ground rules all transforms will follow, so things don't
diff --git a/subx/036recommend_labels.cc b/subx/036recommend_labels.cc
deleted file mode 100644
index 3d603842..00000000
--- a/subx/036recommend_labels.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-//: Now that we have labels, using non-label offsets should be unnecessary.
-//: While SubX will allow programmers to write raw machine code, that isn't
-//: *recommended* once we have more ergonomic alternatives.
-
-:(scenario warn_on_jump_offset)
-== 0x1
-7e/jump-if 1/disp8
-+warn: '7e/jump-if 1/disp8': using raw offsets for jumps is not recommended; use labels instead
-
-:(scenarios transform)
-:(scenario warn_on_call_offset)
-== 0x1
-e8/call 1/disp32
-+warn: 'e8/call 1/disp32': using raw offsets for calls is not recommended; use labels instead
-:(scenarios run)
-
-:(before "Rewrite Labels(segment code)")
-recommend_labels(code);
-if (trace_contains_errors()) return;
-:(code)
-void recommend_labels(const segment& code) {
-  trace(99, "transform") << "-- check for numeric labels" << end();
-  for (int i = 0;  i < SIZE(code.lines);  ++i)
-    recommend_labels(code.lines.at(i));
-}
-
-void recommend_labels(const line& inst) {
-  int idx = first_operand(inst);
-  if (idx >= SIZE(inst.words)) return;
-  if (!is_number(inst.words.at(idx).data)) return;
-  if (is_jump(inst))
-    warn << "'" << inst.original << "': using raw offsets for jumps is not recommended; use labels instead\n" << end();
-  else if (is_call(inst))
-    warn << "'" << inst.original << "': using raw offsets for calls is not recommended; use labels instead\n" << end();
-}
-
-bool is_jump(const line& inst) {
-  string op1 = preprocess_op(inst.words.at(0)).data;
-  if (op1 == "0f") {
-    string op2 = preprocess_op(inst.words.at(1)).data;
-    return Jump_opcodes_0f.find(op1) != Jump_opcodes_0f.end();
-  }
-  if (op1 == "ff") return subop(inst) == /*subop for opcode ff*/4;
-  return Jump_opcodes.find(op1) != Jump_opcodes.end();
-}
-
-bool is_call(const line& inst) {
-  string op1 = preprocess_op(inst.words.at(0)).data;
-  if (op1 == "e8") return true;
-  if (op1 == "ff") return subop(inst) == /*subop for opcode ff*/2;
-  return false;  // no multi-byte call opcodes
-}
-
-int subop(const line& inst) {
-  int idx = first_operand(inst);
-  assert(idx < SIZE(inst.words));
-  return (parse_int(inst.words.at(idx).data)>>3) & 0x7;
-}
-
-:(before "End Globals")
-set<string> Jump_opcodes;
-set<string> Jump_opcodes_0f;
-:(before "End One-time Setup")
-init_jump_opcodes();
-:(code)
-void init_jump_opcodes() {
-  Jump_opcodes.insert("74");
-  Jump_opcodes.insert("75");
-  Jump_opcodes.insert("7c");
-  Jump_opcodes.insert("7d");
-  Jump_opcodes.insert("7e");
-  Jump_opcodes.insert("7f");
-  Jump_opcodes_0f.insert("84");
-  Jump_opcodes_0f.insert("85");
-  Jump_opcodes_0f.insert("8c");
-  Jump_opcodes_0f.insert("8d");
-  Jump_opcodes_0f.insert("8e");
-  Jump_opcodes_0f.insert("8f");
-  Jump_opcodes.insert("e9");
-  Jump_opcodes.insert("eb");
-}
diff --git a/subx/037label_types.cc b/subx/037label_types.cc
deleted file mode 100644
index b80db732..00000000
--- a/subx/037label_types.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-//: Distinguish between labels marking the start of a function, and labels
-//: inside functions.
-//:
-//: - Labels within functions start with a '$', and are only permitted in
-//:   'jump' instructions.
-//:
-//: - Labels marking the start of functions lack the '$' sigil, and are only
-//:   permitted in 'call' instructions.
-
-:(before "Rewrite Labels(segment code)")
-check_label_types(code);
-if (trace_contains_errors()) return;
-:(code)
-void check_label_types(const segment& code) {
-  trace(99, "transform") << "-- check label types" << end();
-  for (int i = 0;  i < SIZE(code.lines);  ++i)
-    check_label_types(code.lines.at(i));
-}
-
-void check_label_types(const line& inst) {
-  int idx = first_operand(inst);
-  if (idx >= SIZE(inst.words)) return;
-  const word& target = inst.words.at(idx);
-  if (is_number(target.data)) return;  // handled elsewhere
-  if (is_jump(inst) && target.data.at(0) != '$')
-    raise << "'" << inst.original << "': jumps should always be to internal labels starting with '$'\n" << end();
-  if (is_call(inst) && target.data.at(0) == '$')
-    raise << "'" << inst.original << "': calls should always be to function labels (not starting with '$')\n" << end();
-}
-
-:(scenario catch_jump_to_function)
-% Hide_errors = true;
-== 0x1
-main:
-7e/jump-if foo/disp8
-foo:
-+error: '7e/jump-if foo/disp8': jumps should always be to internal labels starting with '$'
-
-:(scenario catch_call_to_internal_label)
-% Hide_errors = true;
-== 0x1
-main:
-e8/call $foo/disp32
- $foo:  # indent to avoid looking like a trace_count command for this scenario
-+error: 'e8/call $foo/disp32': calls should always be to function labels (not starting with '$')
diff --git a/subx/038check_local_jumps.cc b/subx/038check_local_jumps.cc
deleted file mode 100644
index 41f8e471..00000000
--- a/subx/038check_local_jumps.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-//: Make sure that we never jump from one function to within another.
-//:
-//: (The check for label types already ensures we can't jump to the start of
-//: another function.)
-
-:(scenario jump_to_different_function)
-% Hide_errors = true;
-== 0x1
-fn1:
-  7e/jump-if $target/disp8
-fn2:
- $target:
-+error: '7e/jump-if $target/disp8' in function 'fn1': jump to within another function 'fn2' is a *really* bad idea
-
-:(before "Rewrite Labels(segment code)")
-check_local_jumps(code);
-if (trace_contains_errors()) return;
-:(code)
-void check_local_jumps(const segment& code) {
-  map</*jump target*/string, /*containing call target*/string> function;
-  compute_function_target(code, function);
-  if (trace_contains_errors()) return;
-  string current_function;
-  for (int i = 0;  i < SIZE(code.lines);  ++i) {
-    const line& inst = code.lines.at(i);
-    if (SIZE(inst.words) == 1 && is_label(inst.words.at(0))) {
-      // label definition
-      if (inst.words.at(0).data.at(0) != '$')
-        current_function = drop_last(inst.words.at(0).data);
-    }
-    else if (is_jump(inst)) {
-      const word& target = inst.words.at(first_operand(inst));
-      if (!contains_key(function, target.data)) continue;  // error/warning handled elsewhere
-      if (get(function, target.data) == current_function) continue;
-      raise << "'" << to_string(inst) << "' in function '" << current_function << "': jump to within another function '" << get(function, target.data) << "' is a *really* bad idea\n" << end();
-      return;
-    }
-  }
-}
-
-void compute_function_target(const segment& code, map<string, string>& out) {
-  string current_function;
-  for (int i = 0;  i < SIZE(code.lines);  ++i) {
-    const line& inst = code.lines.at(i);
-    if (SIZE(inst.words) != 1) continue;
-    const word& curr = inst.words.at(0);
-    if (!is_label(curr)) continue;
-    const string& label = drop_last(curr.data);
-    if (label.at(0) != '$') {
-      current_function = label;
-      continue;
-    }
-    if (contains_key(out, label)) {
-      raise << "duplicate label '" << label << "'\n" << end();
-      return;
-    }
-    // current_function can be empty! if so that would be 'main'.
-    put(out, label, current_function);
-  }
-}
diff --git a/subx/subx.vim b/subx/subx.vim
index e6825c72..454c9454 100644
--- a/subx/subx.vim
+++ b/subx/subx.vim
@@ -25,21 +25,4 @@ let b:cmt_head = "#? "
 " comment token
 syntax match subxDelimiter / \. /  | highlight link subxDelimiter Delimiter
 
-"" highlight low-level idioms in red as I provide more high-level replacements
-
-" Once we have labels, highlight raw displacement
-highlight Warn ctermbg=brown ctermfg=black
-call matchadd("Warn", '\c^\s*e8.*\<\(0x\)\?[0-9a-f]\+/disp32')  " call
-call matchadd("Warn", '\c^\s*e9.*\<\(0x\)\?[0-9a-f]\+/disp8')  " unconditional jump disp8
-call matchadd("Warn", '\c^\s*7[45cdef].*\<\(0x\)\?[0-9a-f]\+/disp8')  " conditional jump disp8
-call matchadd("Warn", '\c^\s*eb.*\<\(0x\)\?[0-9a-f]\+/disp16')  " unconditional jump disp16
-call matchadd("Warn", '\c^\s*0f[^\s]*\s*8[45cdef].*\<\(0x\)\?[0-9a-f]\+/disp16')  " conditional jump disp16
-
-" Mismatch in label type
-call matchadd("Error", '\c^\s*e8.*\$')  " call
-call matchadd("Error", '\c^\s*e9\(/[^ ]*\)\?\s*\(\.\s*\)\+[^\$\. ]\([ \$0-9a-fA-F-]\+\>\)\@!')  " unconditional jump disp8
-call matchadd("Error", '\c^\s*7[45cdef]\(/[^ ]*\)\?\s*\(\.\s*\)\+[^\$\. ]\([ \$0-9a-fA-F-]\+\>\)\@!')  " conditional jump disp8
-call matchadd("Error", '\c^\s*eb\(/[^ ]*\)\?\s*\(\.\s*\)\+[^\$\. ]\([ \$0-9a-fA-F-]\+\>\)\@!')  " unconditional jump disp16
-call matchadd("Error", '\c^\s*0f[^\s]*\s*8[45cdef]\(/[^ ]*\)\?\s*\(\.\s*\)\+[^\$\. ]\([ \$0-9a-fA-F-]\+\>\)\@!')  " conditional jump disp16
-
 let &cpo = s:save_cpo