1# 2# $Id: xkbparser.rb,v 1.1.1.1 2022/10/17 07:37:08 mrg Exp $ 3# 4# Commont parsing classes for symbols/inet 5# The parsing is simplified, based on regex - it is NOT a real parser for very 6# complex XKB format 7# 8 9require "utils.rb" 10 11class Symbols < Hash 12 13 # 14 # Constructor 15 # 16 def initialize 17 @includedSyms = Array.new 18 end 19 20 # Write-only property, parent list of symbols definitions 21 def symbols_list=(symbolsList) 22 @symbolsList = symbolsList 23 end 24 25 # Whether this set of symbols is hidden or not 26 def hidden? 27 @hidden 28 end 29 30 def hidden=(h) 31 @hidden = h 32 end 33 34 # 35 # Add "dependency" - the symbols referenced using the "include" statement. 36 # 37 def add_included(other) 38 @includedSyms.push(other) 39 end 40 41 alias get_original [] 42 alias keys_original keys 43 44 # 45 # Get the symbol, trying first own definitions, then walking through all 46 # dependenies 47 # 48 def [](symName) 49 own = self.get_original(symName) 50 if own.nil? 51 @includedSyms.find_all do | symsName | 52 syms = @symbolsList[symsName] 53 his = syms[symName] 54 if !his.nil? 55 own = his 56 break 57 end 58 end 59 end 60 own 61 end 62 63 # 64 # All keys - including the ones specified in the included sections 65 # 66 def keys() 67 @includedSyms.inject(keys_original) do | rv, symsName | 68 syms = @symbolsList[symsName] 69 rv | syms.keys 70 end 71 end 72 73 # Size of all keys 74 def length() 75 keys().length() 76 end 77 78 # 79 # Size - takes into account overlapping key definitions 80 # 81 def size() 82 keys.size() 83 end 84 85 # 86 # Create a hash including all elements of this hash which are not in the 87 # other hash, use symbols + and * for marking the elements which existed in 88 # the original hash (+ if not existed) 89 # 90 def -(other) 91 diff = self.class.new 92 self.find_all do | key, value | 93 existing = other[key] 94 if existing != value 95 diff[key] = [ value, existing.nil? ? '+' : '' ] 96 end 97 end 98 diff 99 end 100 101 102 def to_s 103 s = "{\n" 104 # First output included syms 105 @includedSyms.find_all do | symsName | 106 s += " include \"inet(#{symsName})\"\n" 107 end 108 # Then - own definitions 109 self.find_all do | key, value | 110 s += " key #{key} { [ #{value} ] };\n" 111 end 112 s + "}"; 113 end 114 115end 116 117class SymbolsList < Hash 118 119 # 120 # Add new xkb_symbols 121 # 122 def add_symbols (symbolsName, hidden) 123 newSyms = Symbols.new 124 newSyms.symbols_list = self 125 newSyms.hidden = hidden 126 self[symbolsName] = newSyms 127 end 128 129 def to_s 130 s = "// Autogenerated\n\n" 131 self.find_all do | symbols, mapping | 132 s += "partial alphanumeric_keys\nxkb_symbols \"#{symbols}\" #{mapping};\n\n" 133 end 134 s 135 end 136 137 def match_symbols(new_symbols,limit) 138 matching = Hash.new 139 find_all do | symbols, mapping | 140 diff = new_symbols - mapping 141 if diff.size <= limit 142 matching[symbols] = diff 143 end 144 end 145 matching 146 end 147 148 def merge() 149 everything = NonuniqueCountingHash.new 150 find_all do | symsName, syms | 151 syms.find_all do | symName, keycode | 152 everything[symName] = keycode 153 end 154 end 155 everything 156 end 157 158end 159 160class Parser 161 162 def parse (fileName) 163 allSyms = SymbolsList.new; 164 currentSyms = nil 165 hidden = false 166 File.open(fileName) do | file | 167 file.each_line do | line | 168 line.scan(/xkb_symbols\s+"(\w+)"/) do | symsName | 169 currentSyms = allSyms.add_symbols(symsName[0], hidden) 170 end 171 line.scan(/^\s*key\s*<(\w+)>\s*\{\s*\[\s*(\w+)/) do | keycode, keysym | 172 currentSyms[keycode] = keysym 173 end 174 line.scan(/^partial\s+(hidden\s+)?alphanumeric_keys/) do | h | 175 hidden = !h[0].nil? 176 end 177 line.scan(/^\s*include\s+"inet\((\w+)\)"/) do | otherPart | 178 currentSyms.add_included(otherPart[0]) 179 end 180 end 181 end 182 allSyms 183 end 184 185end 186