Question

Je construis un analyseur lexical dans Ruby et je suis sur le point de commencer à rassembler et à stocker des symboles dans la table des symboles. Ma principale question sur la conception du symbole et pour savoir s'il doit être un tableau statique (ce qui signifie que toutes les données seront maintenues au niveau de la classe) ou si elle devrait être sur une base d'instance.

Option 1: structure de données au niveau de la classe

require 'SymbolTableEntry.rb'

class SymbolTable
  @sym_table = Array.new(500)
  def initialize()
  end

  def SymbolTable.add(element, index)
    @sym_table[index] = element if element.is_a? SymbolTableEntry
  end

  def SymbolTable.to_s
    pp @sym_table
  end
end

Avec ce schéma, la classe symboltable a une sorte de fonctionnalité «statique», ce qui signifie que je ne crée pas réellement une instance de symboldable, le seul objet qui existe est le niveau de classe.

(Suppose que SymbolTableEntry est un objet valide même si je ne le définis pas ici)

Ex:

irb(main):002:0> require 'SymbolTable.rb'
=> true

irb(main):003:0> ste = SymbolTableEntry.new
=> #<SymbolTableEntry:0x7ef36884>

irb(main):004:0> SymbolTable.add(ste, 10)
=> #<SymbolTableEntry:0x7ef36884>

irb(main):005:0> SymbolTable.to_s
[nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 #<SymbolTableEntry:0x7ef36884>]
=> nil

Option 2: structure de données au niveau de l'instance

require 'rubygems'
require 'backports'
require 'SymbolTableEntry.rb'

class SymbolTable
  def initialize()
    @sym_table = Array.new(10)
  end

  def add(element, index)
    @sym_table[index] = element if element.is_a? SymbolTableEntry
  end

  def to_s
    pp @sym_table
  end
end

Avec ce schéma, je devrais en fait instancier une instance de la classe symboltable afin d'ajouter des valeurs à la table de symboles.

irb(main):001:0> require 'SymbolTable.rb'
=> true

irb(main):002:0> st = SymbolTable.new
=> #<SymbolTable:0x7eeb6c9c @sym_table=[nil, nil, nil, nil, nil, 
                                        nil, nil, nil, nil, nil]>

irb(main):003:0> ste=SymbolTableEntry.new
=> #<SymbolTableEntry:0x7eeb4d5c>

irb(main):004:0> st.add(ste,10)
=> #<SymbolTableEntry:0x7eeb4d5c>

irb(main):007:0> st.to_s
[nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 nil,
 #<SymbolTableEntry:0x7eeb4d5c>]
=> nil

J'aimerais entendre toutes les entrées sur la conception que vous utiliseriez ou préférez utiliser, ainsi que tous les commentaires sur le code Ruby en général.

Merci

Était-ce utile?

La solution

Préférez les variables d'instance aux variables de classe, si pour aucune autre raison que les classes utilisant les variables de classe sont un peu plus douloureuses au test unitaire.

Vous pouvez utiliser des variables d'instance et avoir encore une table de symboles pour les gouverner tous. Une façon consiste en attribuant votre table de symboles à une variable globale:

$symbol_table = SymbolTable.new

Dans certaines langues, les classes qui utilisent des variables globales sont difficiles à tester. Dans Ruby, ils ne sont pas si mauvais, car le typage du canard vous permet d'attribuer des objets simulés aux variables globales avant d'exécuter l'objet testé.

Ou, vous pouvez utiliser le modèle singleton. Ruby est livré avec une bibliothèque pour faciliter cela:

require 'singleton'
class SymbolTable
  include Singleton
  ...
end

Pour récupérer l'instance unique et uniquement de symboldable, l'a créé si nécessaire:

SymbolTable.instance

Autres conseils

Utilisez des variables d'instance. Mais pas (du moins pas seulement) pour des raisons de manipulation des tests. Plutôt parce que

  • Chaque processus d'analyse produira sa propre table de symboles, vous pouvez donc en avoir plus d'un à la fois
  • La table de symboles n'est nécessaire que tant que le processus d'analyse est en cours
  • Les variables de classe introduisent la nécessité de faire une synchronisation pour atteindre la sécurité des fils - même si chaque processus d'analyse peut être parfaitement bien vivre avec son propre ensemble de symboles

Acclamations

Robert

Juste une clarification rapide pour quelques réponses données par Robert et Wayne, qui mentionnent toutes deux Variables de classe.

La question d'origine ne propose pas du tout d'utiliser des variables de classe mais pose des questions sur l'utilisation Variables d'instance de classe. Le premier choix que Hunter a présenté a utilisé l'objet de classe lui-même comme l'instance unique de la table de symbole (avec l'état stocké dans les variables d'instance de classe) tandis que la deuxième option a utilisé un cadre de classe / d'instance plus typique avec l'état stocké dans une instance du symbole table.

Les variables de classe de Ruby ne sont pas la même chose que les variables d'instance de classe et doivent généralement être évitées.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top