# # $Id: xkbparser.rb,v 1.1.1.1 2022/10/17 07:37:08 mrg Exp $ # # Commont parsing classes for symbols/inet # The parsing is simplified, based on regex - it is NOT a real parser for very # complex XKB format # require "utils.rb" class Symbols < Hash # # Constructor # def initialize @includedSyms = Array.new end # Write-only property, parent list of symbols definitions def symbols_list=(symbolsList) @symbolsList = symbolsList end # Whether this set of symbols is hidden or not def hidden? @hidden end def hidden=(h) @hidden = h end # # Add "dependency" - the symbols referenced using the "include" statement. # def add_included(other) @includedSyms.push(other) end alias get_original [] alias keys_original keys # # Get the symbol, trying first own definitions, then walking through all # dependenies # def [](symName) own = self.get_original(symName) if own.nil? @includedSyms.find_all do | symsName | syms = @symbolsList[symsName] his = syms[symName] if !his.nil? own = his break end end end own end # # All keys - including the ones specified in the included sections # def keys() @includedSyms.inject(keys_original) do | rv, symsName | syms = @symbolsList[symsName] rv | syms.keys end end # Size of all keys def length() keys().length() end # # Size - takes into account overlapping key definitions # def size() keys.size() end # # Create a hash including all elements of this hash which are not in the # other hash, use symbols + and * for marking the elements which existed in # the original hash (+ if not existed) # def -(other) diff = self.class.new self.find_all do | key, value | existing = other[key] if existing != value diff[key] = [ value, existing.nil? ? '+' : '' ] end end diff end def to_s s = "{\n" # First output included syms @includedSyms.find_all do | symsName | s += " include \"inet(#{symsName})\"\n" end # Then - own definitions self.find_all do | key, value | s += " key #{key} { [ #{value} ] };\n" end s + "}"; end end class SymbolsList < Hash # # Add new xkb_symbols # def add_symbols (symbolsName, hidden) newSyms = Symbols.new newSyms.symbols_list = self newSyms.hidden = hidden self[symbolsName] = newSyms end def to_s s = "// Autogenerated\n\n" self.find_all do | symbols, mapping | s += "partial alphanumeric_keys\nxkb_symbols \"#{symbols}\" #{mapping};\n\n" end s end def match_symbols(new_symbols,limit) matching = Hash.new find_all do | symbols, mapping | diff = new_symbols - mapping if diff.size <= limit matching[symbols] = diff end end matching end def merge() everything = NonuniqueCountingHash.new find_all do | symsName, syms | syms.find_all do | symName, keycode | everything[symName] = keycode end end everything end end class Parser def parse (fileName) allSyms = SymbolsList.new; currentSyms = nil hidden = false File.open(fileName) do | file | file.each_line do | line | line.scan(/xkb_symbols\s+"(\w+)"/) do | symsName | currentSyms = allSyms.add_symbols(symsName[0], hidden) end line.scan(/^\s*key\s*<(\w+)>\s*\{\s*\[\s*(\w+)/) do | keycode, keysym | currentSyms[keycode] = keysym end line.scan(/^partial\s+(hidden\s+)?alphanumeric_keys/) do | h | hidden = !h[0].nil? end line.scan(/^\s*include\s+"inet\((\w+)\)"/) do | otherPart | currentSyms.add_included(otherPart[0]) end end end allSyms end end