This class specializes the TextScanner class to detect the tokens of the TJP syntax.
# File lib/ProjectFileScanner.rb, line 21 21: def initialize(masterFile, messageHandler) 22: tokenPatterns = [ 23: # Any white spaces 24: [ nil, /\s+/, :tjp, method('newPos') ], 25: 26: # Single line comments starting with # 27: [ nil, /#.*\n?/, :tjp, method('newPos') ], 28: 29: # C++ style single line comments starting with // 30: [ nil, /\/\/.*\n?/, :tjp, method('newPos') ], 31: 32: # C style single line comment /* .. */. 33: [ nil, /\/\*.*\*\//, :tjp, method('newPos') ], 34: 35: # C style multi line comment: We need three patterns here. The first 36: # one is for the start of the string. It switches the scanner mode to 37: # the :cppComment mode. 38: [ nil, /\/\*([^*]*[^\/]|.*)\n/, :tjp, method('startComment') ], 39: # This is the string end pattern. It switches back to tjp mode. 40: [ nil, /.*\*\//, :cppComment, method('endComment') ], 41: # This pattern matches string lines that contain neither the start, 42: # nor the end of the string. 43: [ nil, /^.*\n/, :cppComment ], 44: 45: # Macro Call: This case is more complicated because we want to replace 46: # macro calls inside of numbers, strings and identifiers. For this to 47: # work, macro calls may have a prefix that looks like a number, a part 48: # of a string or an identifier. This prefix is preserved and 49: # re-injected into the scanner together with the expanded text. Macro 50: # calls may span multiple lines. The ${ and the macro name must be in 51: # the first line. Arguments that span multiple lines are not 52: # supported. As above, we need rules for the start, the end and lines 53: # with neither start nor end. Macro calls inside of strings need a 54: # special start pattern that is active in the string modes. Both 55: # patterns switch the scanner to macroCall mode. 56: [ nil, /([-a-zA-Z_0-9>:.+]*|"(\\"|[^"])*?|'(\\'|[^'])*?)?\$\{\s*([a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/, 57: :tjp, method('startMacroCall') ], 58: # This pattern is similar to the previous one, but is active inside of 59: # multi-line strings. The corresponding rule for sizzors strings 60: # can be found below. 61: [ nil, /(\\"|[^"])*?\$\{\s*([a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/, 62: :dqString, method('startMacroCall') ], 63: [ nil, /(\\'|[^'])*?\$\{\s*([a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/, 64: :sqString, method('startMacroCall') ], 65: # This pattern matches the end of a macro call. It injects the prefix 66: # and the expanded macro into the scanner again. The mode is restored 67: # to the previous mode. 68: [ nil, /(\s*"(\\"|[^"])*")*\s*\}/, :macroCall, method('endMacroCall') ], 69: # This pattern collects macro call arguments in lines that contain 70: # neither the start nor the end of the macro. 71: [ nil, /.*\n/, :macroCall, method('midMacroCall') ], 72: 73: # An ID with a colon suffix: foo: 74: [ 'ID_WITH_COLON', /[a-zA-Z_]\w*:/, :tjp, method('chop') ], 75: 76: # An absolute ID: a.b.c 77: [ 'ABSOLUTE_ID', /[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)+/ ], 78: 79: # A normal ID: bar 80: [ 'ID', /[a-zA-Z_]\w*/ ], 81: 82: # A date 83: [ 'DATE', /\d{4}-\d{1,2}-\d{1,2}(-\d{1,2}:\d{1,2}(:\d{1,2})?(-[-+]?\d{4})?)?/, :tjp, method('to_date') ], 84: 85: # A time of day 86: [ 'TIME', /\d{1,2}:\d{2}/, :tjp, method('to_time') ], 87: 88: # A floating point number (e. g. 3.143) 89: [ 'FLOAT', /\d*\.\d+/, :tjp, method('to_f') ], 90: 91: # An integer number 92: [ 'INTEGER', /\d+/, :tjp, method('to_i') ], 93: 94: # Multi line string enclosed with double quotes. The string may 95: # contain double quotes prefixed by a backslash. The first rule 96: # switches the scanner to dqString mode. 97: [ 'nil', /"(\\"|[^"])*/, :tjp, method('startStringDQ') ], 98: # Any line not containing the start or end. 99: [ 'nil', /^(\\"|[^"])*\n/, :dqString, method('midStringDQ') ], 100: # The end of the string. 101: [ 'STRING', /(\\"|[^"])*"/, :dqString, method('endStringDQ') ], 102: 103: # Multi line string enclosed with single quotes. 104: [ 'nil', /'(\\'|[^'])*/, :tjp, method('startStringSQ') ], 105: # Any line not containing the start or end. 106: [ 'nil', /^(\\'|[^'])*\n/, :sqString, method('midStringSQ') ], 107: # The end of the string. 108: [ 'STRING', /(\\'|[^'])*'/, :sqString, method('endStringSQ') ], 109: 110: # Scizzors marked string -8<- ... ->8-: The opening mark must be the 111: # last thing in the line. The indentation of the first line after the 112: # opening mark determines the indentation for all following lines. So, 113: # we first switch the scanner to szrString1 mode. 114: [ 'nil', /-8<-.*\n/, :tjp, method('startStringSZR') ], 115: # Since the first line can be the last line (empty string case), we 116: # need to detect the end in szrString1 and szrString mode. The 117: # patterns switch the scanner back to tjp mode. 118: [ 'STRING', /\s*->8-/, :szrString1, method('endStringSZR') ], 119: [ 'STRING', /\s*->8-/, :szrString, method('endStringSZR') ], 120: # This rule handles macros inside of sizzors strings. 121: [ nil, /.*?\$\{\s*([a-zA-Z_]\w*)(\s*"(\\"|[^"])*")*/, 122: [ :szrString, :szrString1 ], method('startMacroCall') ], 123: # Any line not containing the start or end. 124: [ 'nil', /.*\n/, :szrString1, method('firstStringSZR') ], 125: [ 'nil', /.*\n/, :szrString, method('midStringSZR') ], 126: 127: # Single line macro definition 128: [ 'MACRO', /\[.*\]\n/, :tjp, method('chop2nl') ], 129: 130: # Multi line macro definition: The pattern switches the scanner into 131: # macroDef mode. 132: [ nil, /\[.*\n/, :tjp, method('startMacroDef') ], 133: # The end of the macro is marked by a ']' that is immediately followed 134: # by a line break. It switches the scanner back to tjp mode. 135: [ 'MACRO', /.*\]\n/, :macroDef, method('endMacroDef') ], 136: # Any line not containing the start or end. 137: [ nil, /.*\n/, :macroDef, method('midMacroDef') ], 138: 139: # Some multi-char literals. 140: [ 'LITERAL', /<=?/ ], 141: [ 'LITERAL', />=?/ ], 142: [ 'LITERAL', /!=?/ ], 143: 144: # Everything else is returned as a single-char literal. 145: [ 'LITERAL', /./ ] 146: ] 147: 148: super(masterFile, messageHandler, tokenPatterns, :tjp) 149: end
# File lib/ProjectFileScanner.rb, line 178 178: def chop(type, match) 179: [ type, match[0..2] ] 180: end
# File lib/ProjectFileScanner.rb, line 182 182: def chop2(type, match) 183: # Remove first and last character. 184: [ type, match[1..2] ] 185: end
# File lib/ProjectFileScanner.rb, line 187 187: def chop2nl(type, match) 188: # remove first and last 2 characters. 189: [ type, match[1..3] ] 190: end
# File lib/ProjectFileScanner.rb, line 197 197: def endComment(type, match) 198: self.mode = :tjp 199: [ nil, '' ] 200: end
# File lib/ProjectFileScanner.rb, line 311 311: def endMacroCall(type, match) 312: self.mode = @macroCallPreviousMode 313: @macroCall += match 314: 315: # Store any characters that precede the ${ in prefix and remove it from 316: # @macroCall. 317: if (macroStart = @macroCall.index('${')) > 0 318: prefix = @macroCall[0..(macroStart - 1)] 319: @macroCall = @macroCall[macroStart..1] 320: else 321: prefix = '' 322: end 323: 324: # Remove '${' and '}' 325: argsStr = @macroCall[2..2] 326: # Extract the macro name. 327: if argsStr.index(' ').nil? 328: expandMacro(prefix, [ argsStr ]) 329: else 330: macroName = argsStr[0, argsStr.index(' ')] 331: # Remove the name part from argsStr 332: argsStr = argsStr[macroName.length..1] 333: # Array to hold the arguments 334: args = [] 335: # We use another StringScanner to clean the double quotes. 336: scanner = StringScanner.new(argsStr) 337: while (scanner.scan(/\s*"/)) 338: args << scanner.scan(/(\\"|[^"])*/).gsub(/\\"/, '"') 339: scanner.scan(/"\s*/) 340: end 341: 342: unless scanner.eos? 343: raise "Junk found at end of macro: #{argsStr[scanner.pos..-1]}" 344: end 345: 346: # Expand the macro and inject it into the scanner. 347: expandMacro(prefix, [ macroName ] + args) 348: end 349: 350: [ nil, '' ] 351: end
# File lib/ProjectFileScanner.rb, line 292 292: def endMacroDef(type, match) 293: self.mode = :tjp 294: # Remove "]\n" 295: @macroDef += match[0..3] 296: [ 'MACRO', @macroDef ] 297: end
# File lib/ProjectFileScanner.rb, line 215 215: def endStringDQ(type, match) 216: self.mode = :tjp 217: # Remove the trailing " and remove the backslashes from escaped ". 218: @string += match[0..2].gsub(/\\"/, '"') 219: [ 'STRING', @string ] 220: end
# File lib/ProjectFileScanner.rb, line 235 235: def endStringSQ(type, match) 236: self.mode = :tjp 237: # Remove the trailing ' and remove the backslashes from escaped '. 238: @string += match[0..2].gsub(/\\'/, "'") 239: [ 'STRING', @string ] 240: end
# File lib/ProjectFileScanner.rb, line 275 275: def endStringSZR(type, match) 276: self.mode = :tjp 277: [ 'STRING', @string ] 278: end
# File lib/ProjectFileScanner.rb, line 257 257: def firstStringSZR(type, match) 258: self.mode = :szrString 259: # Split the leading indentation and the rest of the string. 260: @indent, @string = */(\s*)(.*\n)/.match(match)[1, 2] 261: [ nil, '' ] 262: end
# File lib/ProjectFileScanner.rb, line 306 306: def midMacroCall(type, match) 307: @macroCall += match 308: [ nil, '' ] 309: end
# File lib/ProjectFileScanner.rb, line 287 287: def midMacroDef(type, match) 288: @macroDef += match 289: [ nil, '' ] 290: end
# File lib/ProjectFileScanner.rb, line 209 209: def midStringDQ(type, match) 210: # Remove the backslashes from escaped ". 211: @string += match.gsub(/\\"/, '"') 212: [ nil, '' ] 213: end
# File lib/ProjectFileScanner.rb, line 229 229: def midStringSQ(type, match) 230: # Remove the backslashes from escaped '. 231: @string += match.gsub(/\\'/, "'") 232: [ nil, '' ] 233: end
# File lib/ProjectFileScanner.rb, line 264 264: def midStringSZR(type, match) 265: # Ignore all the characters from the begining of match that are the same 266: # in @indent. 267: i = 0 268: while i < @indent.length && @indent[i] == match[i] 269: i += 1 270: end 271: @string += match[i..1] 272: [ nil, '' ] 273: end
# File lib/ProjectFileScanner.rb, line 173 173: def newPos(type, match) 174: @startOfToken = sourceFileInfo 175: [ nil, '' ] 176: end
# File lib/ProjectFileScanner.rb, line 192 192: def startComment(type, match) 193: self.mode = :cppComment 194: [ nil, '' ] 195: end
# File lib/ProjectFileScanner.rb, line 299 299: def startMacroCall(type, match) 300: @macroCallPreviousMode = @scannerMode 301: self.mode = :macroCall 302: @macroCall = match 303: [ nil, '' ] 304: end
# File lib/ProjectFileScanner.rb, line 280 280: def startMacroDef(type, match) 281: self.mode = :macroDef 282: # Remove the opening '[' 283: @macroDef = match[1..1] 284: [ nil, '' ] 285: end
# File lib/ProjectFileScanner.rb, line 202 202: def startStringDQ(type, match) 203: self.mode = :dqString 204: # Remove the opening " and remove the backslashes from escaped ". 205: @string = match[1..1].gsub(/\\"/, '"') 206: [ nil, '' ] 207: end
# File lib/ProjectFileScanner.rb, line 222 222: def startStringSQ(type, match) 223: self.mode = :sqString 224: # Remove the opening ' and remove the backslashes from escaped '. 225: @string = match[1..1].gsub(/\\'/, "'") 226: [ nil, '' ] 227: end
# File lib/ProjectFileScanner.rb, line 242 242: def startStringSZR(type, match) 243: # There should be a line break after the cut mark, but we allow some 244: # spaces between the mark and the line break as well. 245: if match.length != 5 && /-8<-\s*\n$/.match(match).nil? 246: @lineDelta = 1 247: error('junk_after_cut', 248: 'The cut mark -8<- must be immediately followed by a ' + 249: 'line break.') 250: end 251: self.mode = :szrString1 252: @startOfToken = sourceFileInfo 253: @string = '' 254: [ nil, '' ] 255: end
# File lib/ProjectFileScanner.rb, line 169 169: def to_date(type, match) 170: [ type, TjTime.new(match) ] 171: end
# File lib/ProjectFileScanner.rb, line 157 157: def to_f(type, match) 158: [ type, match.to_f ] 159: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.