Class: Semantic::Functions

Inherits:
Hash
  • Object
show all
Defined in:
../lib/semantic_functions.rb

Overview

Parsing and storing of the syntactic functions. The Functions class subclasses the Hash class. It maps nonterminal symbols to its expansion hashes of the semantic functions:


  { 
    "symbol1" => { "expansion1_1"=>[ AttrFn, AttrFn ... ], "expansion1_2"=>[ AttrFn, AttrFn ... ], ... },
    "symbol2" => { "expansion2_1"=>[ AttrFn, AttrFn ... ], "expansion2_2"=>[ AttrFn, AttrFn ... ], ... },     
    ...
  }

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Functions) initialize(semantic = nil)

Load the semantic file. The file has to follow this form:


  symbol1:
    expansion1:
      result1_1 : function1_1
      result1_2 : function1_2
      ...
      result1_N1 : function1_N1
    expansion2:
      result2_1 : function2_1
      ...
      result2_N2 : function2_N2
    ...
    expansionM:
      ...
   symbol2:
   ...
   symbolP:
     ...

where:


   * symbol ... a nonterminal symbol defined by the ABNF grammar (see Mapper::Grammar)
   * expansion ... the expansion of the symbol defined by the grammar. 
                 All terminal symbols are matched by the '$' character. 
                 For instance, the ABNF rule:

                 if-statement = "if(" condition ") {" block "} else {" block "}"

                 is represented by:

                 if-statement:
                   $ condition $ block $ block $:

                 There is another special character '*' which matches all expansions.
   * result ... the semantic attribute of some symbol defined by the semantic function.
              It has the form:
                node.attribute
              where attribute is the identifier of the attribute and node is either
              p (parent node) or ci (child node, i is the index of the child beginning from 0).

              There are reserved attribute identifiers:
              _text  .. represents the text of the terminal symbol or the symbol identifier
                        of the nonterminal symbol
              _valid .. the boolean attribute which restricts the usage of the expansion 
                        (see AttrGrDepthFirst class for details)
   * function ... the semantic function using node.attribute arguments, using the Ruby syntax.

Notes: The ‘_’ identifier is reserved and cannot be used as the attribute name or another variable name. If the attribute’s ‘nil’ value means ‘not defined’. Do not use ‘nil’ as a result of a semantic function.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File '../lib/semantic_functions.rb', line 69

def initialize semantic=nil

  super()

  @attributes = AttrIndices.clone     

  # default ctor
  return if semantic.nil?

  # parsing ctor
  yaml = YAML::load( semantic )
  yaml.keys.sort.each do |symbol|
    rules = yaml[symbol]

    newrules = {}
    rules.each_pair do |expansion,funcs|

      batch = []
      funcs.each_pair do |dest,body|

        target = new_attr_ref dest
        args = Functions.extract_args( body )
        inputs = args.map { |arg| new_attr_ref arg }
        fn = Functions.make_proc( Functions.replace_args(body,args) )

        batch << AttrFn.new( fn, target, inputs, body )
      end

      newrules[expansion] = batch
    end

    store( symbol, newrules ) 
  end

end

Instance Attribute Details

- (Object) attributes (readonly)

Attribute identifier array. It contains all attribute identifiers appearing on both the left and right sides of semantic fuctions. For example:


  [ '_text', '_valid', 'cont', 'def', 'span' ]

Note that reserved identifiers beginning with ‘_’ are always present.



112
113
114
# File '../lib/semantic_functions.rb', line 112

def attributes
  @attributes
end

Class Method Details

+ (Object) extract_args(text)

Extract all arguments from the body of the semantic function.



132
133
134
# File '../lib/semantic_functions.rb', line 132

def Functions.extract_args text
  text.scan( /[\w]+\.[\w]+/ ).uniq
end

+ (Object) make_proc(text)

Compile the semantic function previously processed by the extract_args and replace_args.



144
145
146
# File '../lib/semantic_functions.rb', line 144

def Functions.make_proc text
  eval( "proc { |_| #{text} }" )
end

+ (Object) match_key(rulealt)

Convert the Mapper::RuleAlt into the representing string (the expansion key).



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File '../lib/semantic_functions.rb', line 116

def Functions.match_key rulealt 
  result = rulealt.map do |token|
    case token.type
    when :literal
      '$'
    when :symbol
      token.data
    else
      raise 'Semantic::Functions wrong token type'
    end
  end

  result.join ' '
end

+ (Object) replace_args(text_orig, args)

Replace argument identifiers in the source of the semantic function by the _[i] notation.



137
138
139
140
141
# File '../lib/semantic_functions.rb', line 137

def Functions.replace_args( text_orig, args )
  text = text_orig.clone
  args.each_with_index { |a,i| text.gsub!( a, "_[#{i}]" ) }
  text
end

Instance Method Details

- (Object) new_attr_ref(text)

Convert the textual representation of the attribute to the AttrRef (the inversion is done by the render_attr method). For instance: ‘c1._text’ -> AttrRef.new( 2, 0 ). Note it modifies @attributes if given a new attribute identifier.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File '../lib/semantic_functions.rb', line 159

def new_attr_ref text
  all,node,attr = /^([^.]*)\.([^.].*)$/.match( text ).to_a
  raise "Semantic::Functions wrong node/attribute '#{text}'" if all.nil?

  idx = @attributes.index attr
  if idx.nil?
    idx = @attributes.size       
    @attributes.push attr
  end

  return AttrRef.new( 0, idx ) if node == 'p' 

  raise "Semantic::Functions wrong node '#{text}'" unless node.size > 1 and /^c/ =~ node  
  return AttrRef.new( node[1,node.size-1].to_i+1, idx ) 
end

- (Object) node_expansion(symbol, expansion)

Search for the appropriate semantic functions by the particular nonterminal symbol and the RuleAlt expansion.



149
150
151
152
153
154
# File '../lib/semantic_functions.rb', line 149

def node_expansion( symbol, expansion )
  node = fetch(symbol.data, nil)
  return [] if node.nil?
  batch = deep_copy( node.fetch( Functions.match_key(expansion), [] ) )
  return batch.concat( deep_copy( node.fetch( '*', [] ) ) )
end

- (Object) render_attr(ref)

Convert the AttrRef to the textual representation of the attribute (the inversion is done by the new_attr_ref). For example: AttrRef.new( 0, 1 ) -> ‘p._valid’.



177
178
179
# File '../lib/semantic_functions.rb', line 177

def render_attr ref
  "#{ ref.node_idx==0 ? 'p' : 'c'+(ref.node_idx-1).to_s }.#{ @attributes[ ref.attr_idx ] }"
end