2013-10-12 8 views
6

Hier ist ein Lua-Transkript 5.2.2, die Erklärung und die Indizierung einer Tabelle zeigt:Warum werden Tabellenliterale anders als Tabellenreferenzen in Lua behandelt?

> mylist = {'foo', 'bar'} 
> print(mylist[1]) 
foo 

Warum nicht die folgende Anweisung legal ist?

> print({'foo', 'bar'}[1]) 
stdin:1: ')' expected near '[' 

ich keine andere Sprache denken kann, wo eine wörtliche kann nicht für einen Verweis ersetzt werden (außer natürlich, wenn ein L-Wert erforderlich ist).

FWIW, einklammern die Tabelle wörtliche die Aussage Recht macht:

> print(({'foo', 'bar'})[1]) 
foo 

Antwort

10

Es wird auch auf die Tatsache, dass in Lua diese Syntax gilt:

myfunc { 1, 2, 3 } 

und entspricht:

myfunc({ 1, 2, 3 }) 

daher ein Ausdruck wie:

myfunc { 1, 2, 3 } [2] 

als analysiert:

myfunc({ 1, 2, 3 })[2] 

so zunächst der Funktionsaufruf ausgewertet wird, dann ist die Indizierung stattfindet.

Wenn {1,2,3}[2] als gültige Indexierungsoperation analysiert werden könnte, könnte dies zu Mehrdeutigkeiten im vorherigen Ausdruck führen, die mehr Lookahead erfordern würden. Das Lua-Team entschied sich dafür, den Lua-Bytecode-Compiler schnell zu machen, indem er es zu einem Single-Pass-Compiler machte. Daher scannt es den Quellcode nur einmal mit einem Minimum an Lookahead. This message to lua mailing list from Roberto Ierusalimschy (lead Lua developer) Punkte in diese Richtung.

Dasselbe Problem besteht für Zeichenfolgenliterale und Methodenaufrufe. Dies ist ungültig:

"my literal":sub(1) 

aber gilt:

("my literal"):sub(1) 

Wieder Lua ermöglicht dies:

func "my literal" 

als gleichwertig dazu:

func("my literal") 
+0

+1; das erklärt eigentlich den Grund. Ich bin aber kein Freund der "foo" bar "=> foo (" bar ")" syntaktischer Zucker. – dualed

+1

@dualed Nun, wenn es nur zur Vermeidung eines Paares von Parens verwendet würde, würde ich zustimmen, aber die wahre Macht dieses "Zuckers" ist offensichtlich, wenn man domänenspezifische Sprachen entwirft. Zum Beispiel, etwas wie 'Widget {w = 100, h = 10} "Warnung" "Stapelüberlauf in der Frobnicator!" 'Ist reguläre Lua-Syntax und kann leicht durch die" Widget "-Funktion mit einigen Schließung Tricks geparst werden , ohne einen Parser schreiben zu müssen! Dies kann sehr nützlich sein, wenn Sie Lua als Konfigurationssprache oder für andere Anwendungen verwenden, bei denen Endbenutzer keine erfahrenen Programmierer sind, oder um benutzerdefinierte Datenbeschreibungssprachen zu erstellen. –

+0

Ich stimme überhaupt nicht zu, diese Art von Sachen verwirrt nur einen Benutzer, vor allem, wenn sie einige Fehler machen. Die Fehlermeldung würde für sie niemals Sinn ergeben. Je. Sicherere Verwendung der einfachen Lua-Syntax, einiger existierender plist, xml, ini, du nennst es oder erstellst sogar deine eigenen und schreibst einen echten Parser dafür. – dualed

5

die Grammatik geht here definiert, ist der Grund, dass die nicht eingeklammerten Version ist ungültig noch die geklammerten ist, wird, da der Syntaxbaum nimmt eine anderer Pfad und erwartet eine schließende Klammer ) weil dort sollte kein anderes Symbol in diesem Zusammenhang sein.

Im ersten Fall:

functioncall ::= prefixexp args | prefixexp `:´ Name args 

    prefixexp => 
     prefixexp ::= var | functioncall | `(´ exp `)´ 

      var -> print 
    THEREFORE prefixexp -> print 

    args => 
     args ::= `(´ [explist] `)´ | tableconstructor | String 
      match '(' 

      explist => 
       explist ::= {exp `,´} exp 
        exp => 
         exp ::= nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp 
          tableconstructor => 
        explist-> {'foo','bar'} 

      THEREFORE explist = {'foo','bar'} 

      match ')' ERROR!!! found '[' expected ')' 

Auf der anderen Seite mit Klammern:

functioncall ::= prefixexp args | prefixexp `:´ Name args 

    prefixexp => 
     prefixexp ::= var | functioncall | `(´ exp `)´ 

      var -> print 
    THEREFORE prefixexp -> print 

    args => 
     args ::= `(´ [explist] `)´ | tableconstructor | String 
      match '(' 

      explist => 
       explist ::= {exp `,´} exp 
        exp => 
         exp ::= nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp 
          prefixexp => 
           prefixexp ::= var | functioncall | `(´ exp `)´ 
            var => 
             var ::= Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 
              prefixexp => 
               prefixexp ::= var | functioncall | `(´ exp `)´ 
               match '(' 
               exp => 
                exp ::= nil | false | true | Number | String | `...´ | function | prefixexp | tableconstructor | exp binop exp | unop exp 
                tableconstructor => 
               THEREFORE exp = {'foo','bar'} 
               match ')' 
              THEREFORE prefixexp = ({'foo','bar'}) 
              match '[' 
              exp => Number = 1 
              match ']' 
            THEREFORE VAR = ({'foo','bar'})[1] 
          THEREFORE prefixexp = VAR 
        THEREFOER exp = VAR 
      THEREFORE explist = VAR 
      match ')' 
    THEREFORE args = (VAR) 
=> print(VAR) 
+0

Vielen Dank für die Erklärung und verweist mich auf die Grammatik.Irgendeine Idee, warum sie die Grammatik nicht in der üblichen Weise erstellt haben, Prefixexp loszuwerden und seine RHS in exp zu bewegen? Meine Vermutung ist, dass sie versucht haben, Fehler wie '3 [2]' zur Parse-Zeit statt zur Laufzeit zu erfassen. –

+0

Ich finde es passend, dass ich von einer Sprache, die eher für Anfänger als für erfahrene Programmierer gedacht war, gebissen habe, da ich an der Erstellung von Sprachen gearbeitet habe (wie App Inventor für Android), die absichtlich den erfahrenen Programmierer und nicht den Anfänger überraschen sollten jemand musste überrascht sein. Zum Beispiel verwendet App Inventor wie Lua 1-basierte Listen. –

+2

@espertus Ich bin mir nicht sicher, warum sie sich dafür entschieden haben, es so zu haben. Ich bin diesem ** exacte ** Problem tatsächlich zuvor begegnet und dachte (nachdem ich von vielen Python gekommen bin) * was? Warum denkt Arbeit nicht *. – HennyH

Verwandte Themen