parser.rb
来自「Harvestman-最新版本」· RB 代码 · 共 1,205 行 · 第 1/4 页
RB
1,205 行
@tokenIndex = (@tokenIndex + 1) & 3 token = @tokens[@tokenIndex] (@tokens[@tokenIndex] = token = Token.new) unless token if input.length == 0 #puts "end!!!" return (token.type = $consts["END"]) end cursor_advance = 0 if (match = $fpRegExp.match(input)) puts "Matched here1" token.type = $consts["NUMBER"] token.value = match[0].to_f elsif (match = /\A0[xX][\da-fA-F]+|\A0[0-7]*|\A\d+/.match(input)) puts "Matched here2" token.type = $consts["NUMBER"] token.value = match[0].to_i elsif (match = /\A(\w|\$)+/.match(input)) puts "MATCH: Matched here3 " + input id = match[0] token.type = $keywords[id] || $consts["IDENTIFIER"] token.value = id elsif (match = /\A"(?:\\.|[^"])*"|\A'(?:[^']|\\.)*'/.match(input)) puts "Matched here4" token.type = $consts["STRING"] token.value = match[0].to_s elsif @scanOperand and (match = /\A\/((?:\\.|[^\/])+)\/([gi]*)/.match(input)) puts "Matched here5" token.type = $consts["REGEXP"] token.value = Regexp.new(match[1] ) #, match[2]) elsif (match = $opRegExp.match(input)) puts "Matched here6 " + input op = match[0] if $assignOpsHash[op] && input[op.length, 1] == '=' puts "Token type is ASSIGN" token.type = $consts["ASSIGN"] token.assignOp = $consts[$opTypeNames[op]] cursor_advance = 1 # length of '=' else puts "TOKEN TYPE NOT ASSIGN" #puts $consts[$opTypeNames[op]].to_s + " " + $opTypeNames[op] + " " + op token.type = $consts[$opTypeNames[op]] puts token.type.to_s + " " + self.scanOperand.to_s + " " + $consts["MINUS"].to_s if @scanOperand and (token.type == $consts["PLUS"] || token.type == $consts["MINUS"]) puts "Adding to token type!" token.type += $consts["UNARY_PLUS"] - $consts["PLUS"] end token.assignOp = nil end token.value = op else raise SyntaxError.new("Illegal token", self) end token.start = @cursor puts "Group0 => " + match[0] puts 'Advancing cursor by ' + (match[0].length + cursor_advance).to_s @cursor += match[0].length + cursor_advance token.end = @cursor token.lineno = @lineno puts "Returning " + token.type.to_s return token.type end def unget #puts "start: lookahead: " + @lookahead.to_s + " tokenIndex: " + @tokenIndex.to_s @lookahead += 1 raise SyntaxError.new("PANIC: too much lookahead!", self) if @lookahead == 4 @tokenIndex = (@tokenIndex - 1) & 3 #puts "end: lookahead: " + @lookahead.to_s + " tokenIndex: " + @tokenIndex.to_s return nil endendclass SyntaxError def initialize (msg, tokenizer) puts msg puts "on line " + tokenizer.lineno.to_s endendclass Token attr_accessor :type, :value, :start, :end, :lineno, :assignOpendclass CompilerContext attr_accessor :inFunction, :stmtStack, :funDecls, :varDecls attr_accessor :bracketLevel, :curlyLevel, :parenLevel, :hookLevel attr_accessor :ecmaStrictMode, :inForLoopInit def initialize (inFunction) @inFunction = inFunction @stmtStack = [] @funDecls = [] @varDecls = [] @bracketLevel = @curlyLevel = @parenLevel = @hookLevel = 0 @ecmaStrictMode = @inForLoopInit = false endendclass Node < Array attr_accessor :type, :value, :lineno, :start, :end, :tokenizer, :initializer attr_accessor :name, :params, :funDecls, :varDecls, :body, :functionForm attr_accessor :assignOp, :expression, :condition, :thenPart, :elsePart attr_accessor :readOnly, :isLoop, :setup, :postfix, :update, :exception attr_accessor :object, :iterator, :varDecl, :label, :target, :tryBlock attr_accessor :catchClauses, :varName, :guard, :block, :discriminant, :cases attr_accessor :defaultIndex, :caseLabel, :statements, :statement def initialize (t, type = nil) token = t.token if token if type != nil @type = type else @type = token.type end @value = token.value @lineno = token.lineno @start = token.start @end = token.end else @type = type @lineno = t.lineno end @tokenizer = t #for (var i = 2; i < arguments.length; i++) #this.push(arguments[i]); end alias superPush push # Always use push to add operands to an expression, to update start and end. def push (kid) if kid.start and @start @start = kid.start if kid.start < @start end if kid.end and @end @end = kid.end if @end < kid.end end return superPush(kid) end# def to_s# a = []# # #for (var i in this) {# # if (this.hasOwnProperty(i) && i != 'type')# # a.push({id: i, value: this[i]});# #}# #a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; });# iNDENTATION = " "# n = (Node.indentLevel += 1)# t = $tokens[@type]# s = "{\n" + iNDENTATION.repeat(n) +# "type: " + (/^\W/.test(t) and opTypeNames[t] or t.upcase)# #for (i = 0; i < a.length; i++)# # s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value# s += ",\n" + iNDENTATION.repeat(n) + @value + ": " + a[i].value# n = (Node.indentLevel -= 1)# s += "\n" + iNDENTATION.repeat(n) + "}"# return s# end def to_s attrs = [@value, @lineno, @start, @end, @name, @params, @funDecls, @varDecls, @body, @functionForm, @assignOp, @expression, @condition, @thenPart, @elsePart] #puts $tokens[@condition.type] if @condition != nil #if /\A[a-z]/ =~ $tokens[@type] # identifier # print @tokenizer.source.slice($cursor, @start - $cursor) if $cursor < @start # print '<span class="identifier">' # print @tokenizer.source.slice(@start, $tokens[@type].length) # print '</span>' # $cursor = @start + $tokens[@type].length #end #puts (" " * $ind) + "{" + $tokens[@type] + "\n" if /\A[a-z]/ =~ $tokens[@type] #puts (" " * $ind) + " " + @start.to_s + "-" + @end.to_s + "\n" $ind += 1 #puts @value self.length.times do |i| self[i].to_s if self[i] != self and self[i].class == Node end attrs.length.times do |attr| if $tokens[@type] == "if" # puts $tokens[attrs[attr].type] if attrs[attr].class == Node and attrs[attr] !== self end attrs[attr].to_s if attrs[attr].class == Node #and attrs[attr] != self #puts (" " * $ind).to_s + attrs[attr].to_s if attrs[attr].to_s != nil and attrs[attr] != self end $ind -= 1 #puts "\n}\n" if $ind == 0 print @tokenizer.source.slice($cursor, @tokenizer.source.length - $cursor) end return "" end def getSource return @tokenizer.source.slice(@start, @end) end def filename return @tokenizer.filename endend$cursor = 0$ind = 0def Script (t, x) n = Statements(t, x) n.type = $consts["SCRIPT"] n.funDecls = x.funDecls n.varDecls = x.varDecls return nend# Statement stack and nested statement handler.# nb. Narcissus allowed a function reference, here we use Statement explicitlydef nest (t, x, node, end_ = nil) x.stmtStack.push(node) n = Statement(t, x) x.stmtStack.pop end_ and t.mustMatch(end_) return nenddef Statements (t, x) n = Node.new(t, $consts["BLOCK"]) x.stmtStack.push(n) n.push(Statement(t, x)) while !t.done and t.peek != $consts["RIGHT_CURLY"] x.stmtStack.pop return nenddef Block (t, x) t.mustMatch($consts["LEFT_CURLY"]) n = Statements(t, x) t.mustMatch($consts["RIGHT_CURLY"]) return nendDECLARED_FORM = 0EXPRESSED_FORM = 1STATEMENT_FORM = 2def Statement (t, x) tt = t.get puts "TT is " + tt.to_s # Cases for statements ending in a right curly return early, avoiding the # common semicolon insertion magic after this switch. case tt when $consts["FUNCTION"] puts "TT is a function" return FunctionDefinition(t, x, true, (x.stmtStack.length > 1) && STATEMENT_FORM || DECLARED_FORM) when $consts["LEFT_CURLY"] n = Statements(t, x) t.mustMatch($consts["RIGHT_CURLY"]) return n when $consts["IF"] n = Node.new(t) n.condition = ParenExpression(t, x) x.stmtStack.push(n) n.thenPart = Statement(t, x) n.elsePart = t.match($consts["ELSE"]) ? Statement(t, x) : nil x.stmtStack.pop() return n when $consts["SWITCH"] n = Node.new(t) t.mustMatch($consts["LEFT_PAREN"]) n.discriminant = Expression(t, x) t.mustMatch($consts["RIGHT_PAREN"]) n.cases = [] n.defaultIndex = -1 x.stmtStack.push(n) t.mustMatch($consts["LEFT_CURLY"]) while (tt = t.get) != $consts["RIGHT_CURLY"] case tt
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?