Class | MathML::LaTeX::Parser |
In: |
lib/math_ml/latex.rb
|
Parent: | Object |
BUILTIN_MACRO | = | <<'EOS' \newenvironment{smallmatrix}{\begin{matrix}}{\end{matrix}} \newenvironment{pmatrix}{\left(\begin{matrix}}{\end{matrix}\right)} \newenvironment{bmatrix}{\left[\begin{matrix}}{\end{matrix}\right]} \newenvironment{Bmatrix}{\left\{\begin{matrix}}{\end{matrix}\right\}} \newenvironment{vmatrix}{\left|\begin{matrix}}{\end{matrix}\right|} \newenvironment{Vmatrix}{\left\|\begin{matrix}}{\end{matrix}\right\|} EOS |
macro | [R] | |
symbol_table | [R] | |
unsecure_entity | [RW] |
# File lib/math_ml/latex.rb, line 366 366: def initialize(opt={}) 367: @unsecure_entity = false 368: @entities = Hash.new 369: @commands = Hash.new 370: @symbols = Hash.new 371: @delimiters = Array.new 372: @group_begins = Hash.new 373: @group_ends = Hash.new 374: @macro = Macro.new 375: @macro.parse(BUILTIN_MACRO) 376: @expanded_command = Array.new 377: @expanded_environment = Array.new 378: @symbol_table = opt[:symbol] || MathML::Symbol::Default 379: @symbol_table = MathML::Symbol::MAP[@symbol_table] if @symbol_table.is_a?(::Symbol) 380: 381: super() 382: end
# File lib/math_ml/latex.rb, line 415 415: def add_commands(*a) 416: if a.size==1 && Hash===a[0] 417: @commands.merge!(a[0]) 418: else 419: a.each{|i| @commands[i] = false} 420: end 421: end
# File lib/math_ml/latex.rb, line 431 431: def add_delimiter(list) 432: @delimiters.concat(list) 433: end
# File lib/math_ml/latex.rb, line 384 384: def add_entity(list) 385: list.each do |i| 386: @entities[i] = true 387: end 388: end
# File lib/math_ml/latex.rb, line 435 435: def add_group(begin_name, end_name, method=nil) 436: @group_begins[begin_name] = method 437: @group_ends[end_name] = begin_name 438: end
# File lib/math_ml/latex.rb, line 423 423: def add_multi_command(m, *a) 424: a.each{|i| @commands[i] = m} 425: end
# File lib/math_ml/latex.rb, line 427 427: def add_sym_cmd(hash) 428: @symbols.merge!(hash) 429: end
# File lib/math_ml/latex.rb, line 390 390: def parse(src, displaystyle=false) 391: @ds = displaystyle 392: begin 393: parse_into(src, Math.new(@ds), Font::NORMAL) 394: rescue ParseError => e 395: e.done = src[0...(src.size - e.rest.size)] 396: raise 397: end 398: end
# File lib/math_ml/latex.rb, line 400 400: def push_container(container, scanner=@scanner, font=@font) 401: data = [@container, @scanner, @font] 402: @container, @scanner, @font = [container, scanner, font] 403: begin 404: yield container 405: container 406: ensure 407: @container, @scanner, @font = data 408: end 409: end
# File lib/math_ml/latex.rb, line 591 591: def entitize(str) 592: MathML.pcstring(str.sub(/^(.*)$/){"&#{$1};"}, true) 593: end
# File lib/math_ml/latex.rb, line 467 467: def parse_any(message = "Syntax error.") 468: raise ParseError.new(message) unless @scanner.scan_any 469: s = @scanner 470: @scanner = Scanner.new(@scanner.matched) 471: begin 472: parse_to_element 473: ensure 474: @scanner = s 475: end 476: end
# File lib/math_ml/latex.rb, line 537 537: def parse_block 538: os = @scanner 539: @scanner = Scanner.new(@scanner[1]) 540: begin 541: push_container(Row.new) do |r| 542: r << parse_to_element(true) until @scanner.eos? 543: end 544: rescue ParseError => e 545: e.rest << '}' 546: raise 547: ensure 548: @scanner = os 549: end 550: end
# File lib/math_ml/latex.rb, line 512 512: def parse_char 513: c = @scanner.matched 514: i = Identifier.new 515: case @font 516: when Font::ROMAN 517: i.extend(Variant).variant = Variant::NORMAL 518: when Font::BOLD 519: i.extend(Variant).variant = Variant::BOLD 520: when Font::BOLD_ITALIC 521: i.extend(Variant).variant = Variant::BOLD_ITALIC 522: when Font::BLACKBOLD 523: c = symbol_table.convert("#{c}opf") 524: when Font::SCRIPT 525: c = symbol_table.convert("#{c}scr") 526: when Font::FRAKTUR 527: c = symbol_table.convert("#{c}fr") 528: end 529: i << c 530: end
# File lib/math_ml/latex.rb, line 639 639: def parse_command 640: com = @scanner[1] 641: matched = @scanner.matched 642: pos = @scanner.pos-matched.size 643: macro = @macro.commands(com) 644: if macro 645: begin 646: flg = @expanded_command.include?(com) 647: @expanded_command.push(com) 648: raise CircularReferenceCommand if flg 649: option = (macro.option && @scanner.scan_option) ? @scanner[1] : nil 650: params = Array.new 651: (1..macro.num).each do 652: params << (@scanner.scan_block ? @scanner[1] : @scanner.scan_any) 653: raise ParseError.new("Need more parameter.") unless params.last 654: end 655: r = parse_into(@macro.expand_command(com, params, option), Array.new) 656: return r 657: rescue CircularReferenceCommand 658: if @expanded_command.size>1 659: raise 660: else 661: @scanner.pos = pos 662: raise ParseError.new("Circular reference.") 663: end 664: rescue ParseError => e 665: if @expanded_command.size>1 666: raise 667: else 668: @scanner.pos = pos 669: raise ParseError.new(%[Error in macro(#{e.message} "#{e.rest.strip}").]) 670: end 671: ensure 672: @expanded_command.pop 673: end 674: elsif @commands.key?(com) 675: m = @commands[com] 676: m = com unless m 677: return __send__("cmd_#{m.to_s}") 678: end 679: parse_symbol_command(com) 680: end
# File lib/math_ml/latex.rb, line 692 692: def parse_group 693: font = @font 694: begin 695: g = @group_begins[@scanner[1]] 696: g = @scanner[1] unless g 697: __send__("grp_#{g.to_s}") 698: ensure 699: @font = font 700: end 701: end
# File lib/math_ml/latex.rb, line 441 441: def parse_into(src, parent, font=nil) 442: orig = [@scanner, @container, @font, @ds] 443: @scanner = Scanner.new(src) 444: @container = parent 445: @font = font if font 446: begin 447: until @scanner.eos? 448: @container << parse_to_element(true) 449: end 450: @container 451: rescue BlockNotClosed => e 452: raise ParseError.new("Block not closed.", @scanner.rest) 453: rescue NotEnvironment => e 454: raise ParseError.new("Not environment.", @scanner.rest) 455: rescue EnvironmentNotEnd => e 456: raise ParseError.new("Environment not end.", @scanner.rest) 457: rescue OptionNotClosed => e 458: raise ParseError.new("Option not closed.", @scanner.rest) 459: rescue ParseError => e 460: e.rest << @scanner.rest.to_s 461: raise 462: ensure 463: @scanner, @container, @font, @ds = orig 464: end 465: end
# File lib/math_ml/latex.rb, line 682 682: def parse_mathfont(font) 683: f = @font 684: @font = font 685: begin 686: push_container(Row.new){|r| r << parse_any} 687: ensure 688: @font = f 689: end 690: end
# File lib/math_ml/latex.rb, line 506 506: def parse_num 507: n = Number.new 508: n.extend(Variant).variant = Variant::BOLD if @font==Font::BOLD 509: n << @scanner.matched 510: end
# File lib/math_ml/latex.rb, line 532 532: def parse_operator 533: o = @scanner.matched 534: Operator.new << o 535: end
# File lib/math_ml/latex.rb, line 552 552: def parse_sub 553: e = @container.pop 554: e = None.new unless e 555: e = SubSup.new(@ds && e.display_style, e) unless e.is_a?(SubSup) 556: raise ParseError.new("Double subscript.", "_") if e.sub 557: e.sub = parse_any("Subscript not exist.") 558: e 559: end
# File lib/math_ml/latex.rb, line 561 561: def parse_sup 562: e = @container.pop 563: e = None.new unless e 564: e = SubSup.new(@ds && e.display_style, e) unless e.is_a?(SubSup) 565: raise ParseError.new("Double superscript.", @scanner[0]) if e.sup 566: if /'+/=~@scanner[0] 567: prime = Operator.new 568: @scanner[0].size.times do 569: prime << symbol_table.convert("prime") 570: end 571: unless @scanner.scan(/\^/) 572: e.sup = prime 573: return e 574: end 575: end 576: sup = parse_any("Superscript not exist.") 577: 578: if prime 579: unless sup.is_a?(Row) 580: r = Row.new 581: r << sup 582: sup = r 583: end 584: sup.contents.insert(0, prime) 585: end 586: 587: e.sup = sup 588: e 589: end
# File lib/math_ml/latex.rb, line 595 595: def parse_symbol_command(com, plain=false) 596: unless @symbols.include?(com) 597: @scanner.pos = @scanner.pos-(com.size+1) 598: raise ParseError.new("Undefined command.") 599: end 600: data = @symbols[com] 601: return nil unless data 602: 603: data, s = data 604: su = data[0] 605: el = data[1] 606: el = :o unless el 607: s = com.dup.untaint.to_sym unless s 608: s = com if s.is_a?(String) && s.length==0 609: 610: case el 611: when :I 612: el = Identifier.new 613: when :i 614: el = Identifier.new 615: el.extend(Variant).variant = Variant::NORMAL unless s.is_a?(String)&&s.length>1 616: when :o 617: el = Operator.new 618: when :n 619: el = Number.new 620: else 621: raise ParseError.new("Inner data broken.") 622: end 623: 624: case s 625: when Fixnum 626: s = MathML.pcstring("&\#x#{s.to_s(16)};", true) 627: when ::Symbol 628: s = symbol_table.convert(s) 629: else 630: MathML.pcstring(s, true) 631: end 632: 633: return s if plain 634: el << s 635: el.as_display_style if su==:u 636: el 637: end
# File lib/math_ml/latex.rb, line 478 478: def parse_to_element(whole_group = false) 479: if whole_group && @group_begins.has_key?(@scanner.peek_command) 480: @scanner.scan_command 481: parse_group 482: else 483: case 484: when @scanner.scan(RE::NUMERICS) 485: parse_num 486: when @scanner.scan(RE::ALPHABETS) 487: parse_char 488: when @scanner.scan(RE::OPERATORS) 489: parse_operator 490: when @scanner.scan_block 491: parse_block 492: when @scanner.scan(/_/) 493: parse_sub 494: when @scanner.scan(/'+|\^/) 495: parse_sup 496: when @scanner.scan(/~/) 497: Space.new("1em") 498: when @scanner.scan_command 499: parse_command 500: else 501: raise ParseError.new('Syntax error.') 502: end 503: end 504: end