spec03
)?
fnt
(standing for ``field-name table'').
<*>= [D->] global fnt # field -> name -> value
Definesfnt
(links are to index).
<*>+= [<-D->] procedure fieldinfo(f, info) initial { /fnt := table(); /fieldasm := table() } case type(info) of { "string" : case info of { "checked" : { <makef
checked> } "unchecked" : { <makef
unchecked> } "guaranteed" : { <makef
guaranteed> } default : { <complain about fieldspecinfo
> } } "namespec" : (/fnt[f] := check_namespec(info, f)) | error("Field names for field ", f.name, " already specified") default : fail } return end
Definesfieldinfo
(links are to index).
<make f
checked>= (<-U)
every delete(guaranteed_fields | unchecked_fields, f)
<make f
unchecked>= (<-U)
insert(unchecked_fields, f)
delete(guaranteed_fields, f)
<make f
guaranteed>= (<-U)
every insert(guaranteed_fields | unchecked_fields, f)
<complain about fieldspec info
>= (<-U)
error("Unknown field info specifier `", info, "'")
Fields can be checked or unchecked at assembly time.
<*>+= [<-D->] global unchecked_fields, guaranteed_fields
Definesguaranteed_fields
,unchecked_fields
(links are to index).
Field values may be assigned pneumonic names that are used during disassembly of instructions. The names bound to field values within an enumeration are used to synthesize the sames of opcodes.
<*>+= [<-D->] record namespec(nametable, full) procedure sparse_name_table(bindlist) t := table() every b := !bindlist do (/t[b.name] := b.val) | error("duplicate field names") return namespec(t) end
Definesnamespec
,sparse_name_table
(links are to index).
<*>+= [<-D->] record enumbinding(name, val)
Definesenumbinding
(links are to index).
<*>+= [<-D->] procedure full_name_table(namelist, f) t := table() every i := 1 to *namelist do (/t[namelist[i]] := i - 1) | error("duplicate field names") return namespec(t, 1) end
Definesfull_name_table
(links are to index).
<*>+= [<-D->] procedure check_namespec(spec, f) if \spec.full then *spec.nametable = 2^fwidth(f) | error("Field ", f.name, " has ", 2^fwidth(f), " values, not ", *spec.nametable) if x := spec.nametable[n := key(spec.nametable)] & (x < 0 | x >= 2^fwidth(f)) then error("name ", image(n), " = ", x, " falls outside the value range of field ", f.name) return spec.nametable end
Definescheck_namespec
(links are to index).
<*>+= [<-D->] procedure fieldname_table(f) initial /fnt := table() return fnt[f] end
Definesfieldname_table
(links are to index).
<*>+= [<-D->] procedure fieldname_env_for(f) return [\fieldname_table(f)] | [] end procedure fieldname_env_for_ipt(ipt) return (type(ipt.meaning) == "field", fieldname_env_for(ipt.meaning)) | [] end
Definesfieldname_env_for
,fieldname_env_for_ipt
(links are to index).
namearray
and pass it to pretty
.
<*>+= [<-D->]
procedure emit_fieldnames(base)
local header, data, fields
data := open(base || implementation_extension, "w")
header := open(base || interface_extension, "w");
if interface_extension == ".h" then
write(data, "#include \"", base, interface_extension, "\"")
pp := PPnew(data);
<make fields
an array of all fields sorted by name>
every PPxwrite(pp, pretty(Gdeclnamearray(fieldnamearray(!fields))), ";")
every write(header, "extern char *", (!fields).name, "_names[];")
every close(data | header)
return
end
Definesemit_fieldnames
(links are to index).
<make fields
an array of all fields sorted by name>= (<-U)
t := table()
fields := []
every f := !symtab & type(f) == "field" do t[f.name] := f
every put(fields, (!sort(t))[2])
To build a name array, we first create a table of all invalid field values.
The valid ones are then overwritten using names from
fieldname_table(f)
.
<*>+= [<-D->] procedure fieldnamearray(f) return name_array_from_table(\fieldname_table(f), 2^fwidth(f), f.name) end procedure name_array_from_table(t, limit, fieldname) local name limit <= 1024 | error("Tried to enumerate ", limit, " names for field or operand ", fieldname) na := namearray(field, table(), limit, fieldname || "_names", "") every i := 0 to na.hi - 1 do na.tbl[i] := bad_operand_name(fieldname, i) every name := key(t) do na.tbl[t[name]] := name return na end procedure bad_operand_name(name, value) return "??" || name || "=" || value || "?!" end
Definesbad_operand_name
,fieldnamearray
,name_array_from_table
(links are to index).
For use in identifying fields with identical naming patterns, we have to turn a name table into a suitable string. This means covering the keys in order.
<*>+= [<-D] procedure nametablekey(nametab) local min, max static cache initial cache := table() if \cache[nametab] then return cache[nametab] if /nametab then return cache[f] := "(no name table)" u := table() every k := key(nametab) do u[nametab[k]] := k <makemin
andmax
smallest and largest values innametab
> s := "" every i := min to max do s ||:= \u[i] || "@" || i || "\0" return cache[f] := s end
Definesnametablekey
(links are to index).
<makemin
andmax
smallest and largest values innametab
>= (<-U) min := max := !nametab | 0 every min >:= !nametab every max <:= !nametab
info
>: U1, D2
f
checked>: U1, D2
f
guaranteed>: U1, D2
f
unchecked>: U1, D2
fields
an array of all fields sorted by name>: U1, D2
min
and max
smallest and largest values in nametab
>: U1, D2