dollarHex) $alts[] = '\$[0-9A-Fa-f]+(?![\w.])'; if ($this->percentBinary) $alts[] = '%[01]+(?![\w.])'; return $this->immediatePrefix.'-?(?:'.implode('|', $alts).')'; } public function classify(string $word, array $ctx): ?string { if ($word === '.' || $word === '$') return null; $key = strtolower($word); // ラベル(「名前:」、又は「名前 db …」「名前 = …」の様な定義) if ($ctx['next'] === ':' && ($ctx['first'] || $ctx['bol'])) return 'label'; if ($ctx['first'] && ($ctx['next'] === '=' || $this->lookup(strtolower($ctx['nextWord'])) === 'directive')) return 'label'; $atOpcode = $ctx['first'] || in_array(strtolower($ctx['prevWord']), $this->prefixes, true); $class = $this->lookup($key); if ($class !== null) { // 命令の位置以外の命令名はシンボルの可能性が高い(例:「jmp add」) if ($class === 'instruction' && !$atOpcode) return null; return $class; } if ($this->percentMacros && $key[0] === '%' && strlen($key) > 1) return 'preprocessor'; if ($key[0] === '.') { // 「.section .text」の様に指令の行なら指令、「jne .done」の様に命令の行ならローカルラベルの参照 if ($atOpcode) return 'directive'; $head = strtolower($ctx['lineWord']); return ($head !== '' && ($head[0] === '.' || $this->lookup($head) === 'directive')) ? 'directive' : null; } if ($atOpcode) return 'instruction'; return null; } /** * 単語表・接尾辞・接頭辞を返す(汎用のAsmがまとめる為) * * @return array [単語 => 種類, 接尾辞の正規表現, 接頭辞] */ public function getTables(): array { return [$this->words, $this->suffixes, $this->prefixes]; } /** * 単語を一覧から探す(接頭辞「%」「$」と接尾辞を外した候補も試す) * * @param string $key 小文字の単語 * @return string|null 種類 */ protected function lookup(string $key): ?string { if ($key === '') return null; $base = ltrim($key, '%$'); foreach ($this->candidates($key) as $c) { if (!isset($this->words[$c])) continue; $class = $this->words[$c]; // 接尾辞を外した候補は命令・指令だけ(「v0.4s」の様に「.」で区切った場合はレジスターも) // そうしないと「hello」→「hel」+「lo」の様な誤判定が起きる if ($c !== $key && $c !== $base && $class !== 'instruction' && $class !== 'directive' && !str_contains($key, '.')) continue; return $class; } return null; } /** * 接頭辞・接尾辞を外した候補を作る * * @param string $key 小文字の単語 * @return array 候補(元の単語が最初) */ protected function candidates(string $key): array { $cands = [$key]; if (strlen($key) > 1 && ($key[0] === '%' || $key[0] === '$')) $cands[] = substr($key, 1); foreach ($this->suffixes as $re) { foreach ($cands as $c) { $s = preg_replace($re, '', $c); if ($s !== null && $s !== '' && $s !== $c) $cands[] = $s; } } return array_values(array_unique($cands)); } }