Guest User

Untitled

a guest
Apr 20th, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.76 KB | None | 0 0
  1. require 'grammar_wirth'
  2. require 'pp'
  3.  
  4. NONTERMINAL = /[a-zA-Z][a-zA-Z_]*/
  5. TERMINAL = /".+"/
  6. RULES = /.*\./
  7. RULE = /(?:([a-zA-Z][a-zA-Z_]*)\s*=)?\s*(.+\.)\n?/
  8.  
  9. TOKENS = {
  10. "(" => "LPAR",
  11. ")" => "RPAR",
  12. "{" => "LCUR",
  13. "}" => "RCUR",
  14. "[" => "LBRA",
  15. "]" => "RBRA",
  16. "=" => "ASSIGN",
  17. "+=" => "ADD_ASSIGN",
  18. "-=" => "SUB_ASSIGN",
  19. "*=" => "MULT_ASSIGN",
  20. "/=" => "DIV_ASSIGN",
  21. "**=" => "PWR_ASSIGN",
  22. "%=" => "MOD_ASSIGN",
  23. "<" => "LT",
  24. ">" => "GT",
  25. "<=" => "LE",
  26. ">=" => "GE",
  27. "!=" => "NE",
  28. "==" => "EQ",
  29. "*" => "MULT",
  30. "+" => "ADD",
  31. "-" => "SUB",
  32. "/" => "DIV",
  33. "%" => "MOD",
  34. "**" => "PWR",
  35. ".." => "RANGE"
  36. }
  37.  
  38. TEMPLATE = <<-CODE
  39. void %nonterminal%()
  40. {
  41. while (true) {
  42. int current_state = 0;
  43. switch (current_state) {
  44. %transitions%
  45. default:
  46. fatal_error("unexpected state");
  47. break;
  48. }
  49. }
  50. }
  51. CODE
  52.  
  53. def submachine_codegen(input, to)
  54. <<-EOF
  55. #{input}(); /* CALL SUB MACHINE */
  56. current_state = #{to};
  57. EOF
  58. end
  59.  
  60. def token_codegen(input, to)
  61. if input.eql?("ANY_CHAR")
  62. <<-EOF
  63. if (' ' <= ch && ch <= '~')
  64. current_state = #{to};
  65. EOF
  66. else
  67. input = TOKENS[input] if TOKENS.has_key?(input)
  68. input = '"\""' if input.eql?('"')
  69. input = %q["'"] if input.eql?("'")
  70. <<-EOF
  71. if (token->class == #{input})
  72. current_state = #{to};
  73. EOF
  74. end
  75. end
  76.  
  77. lexer = <<-LEXER
  78. string = """ { "any_char" } """ | "'" { "any_char" } "'".
  79. op_assign = "=" | "+=" | "/=" | "-=" | "%=" | "**=" .
  80. op_expr = "<" | ">" | ">=" | "<=" | "!=" | "==" | "+" | "-" | "/" | "*" | "%" | "**" | "..".
  81. integer = digit { digit }.
  82. float = digit { digit } "." digit { digit }.
  83. operation = identifier [ "!" | "?" ].
  84. identifier = ( "_" | letter | letter ) { "_" | letter | digit }.
  85. number = digit { digit }.
  86. LEXER
  87.  
  88. file = File.new("lexer.c", "w")
  89. output = ""
  90. lexer.scan(RULES).each do |r|
  91. name, decl = RULE.match(r).captures
  92. w = Grammar::Wirth.new(decl)
  93. dfa = w.minimized_dfa
  94. dfa[:states].each do |state|
  95. output << " case #{state}:\n"
  96. moves = []
  97. first = true
  98. dfa[:transitions][state].each do |transition|
  99. input, to = transition
  100. data = /"(.+)"/.match(input)
  101. if first
  102. output << " ch = readc(in);\n"
  103. first = false
  104. end
  105. if not data.nil?
  106. moves << token_codegen(data.captures.first.upcase, to)
  107. else
  108. moves << submachine_codegen(input, to)
  109. end
  110. end
  111. output << moves.join(' else ')
  112. if moves.size > 1
  113. output << %q[ else
  114. fatal_error("Syntax Error");
  115. ]
  116. end
  117.  
  118. output << " return; /* ACCEPT */\n" if dfa[:final].include?(state)
  119. output << " break;\n"
  120. end
  121.  
  122.  
  123. file << TEMPLATE.sub('%nonterminal%', name).sub('%transitions%', output).gsub(/else\s+if/, "else if")
  124.  
  125. end
  126. file.close
Add Comment
Please, Sign In to add comment