about summary refs log tree commit diff stats
path: root/subx/037label_types.cc
blob: b80db7329abd8f522283fd5fefa9c48535469c27 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//: 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 '$')