Sie sind Professor für Informatik und unterrichten die Programmiersprache C. Ein Prinzip, das Sie den Schülern vermitteln möchten, ist die Modularität . Leider haben frühere Klassen die Nachricht nicht erhalten und Aufgaben mit dem gesamten Programm eingereicht main()
. Daher haben Sie für dieses Semester strenge Modularitätsrichtlinien herausgegeben, nach denen die Studierenden benotet werden.
Eine Teilmenge der C-Grammatik und Regeln für "wohlgeformte" Übersetzungseinheiten sind unten definiert. Code, der diesen Regeln folgt, sollte C89 gültig sein, WENN kein Bezeichner verwendet wird, der ein Schlüsselwort ist.
Aufgabe
Sie erhalten als Eingabe eine Zeichenfolge, die angeblich C-Code enthält. Sie können davon ausgehen, dass diese Zeichenfolge nur Leerzeichen, Zeilenumbrüche und Zeichen enthält abcdefghijklmnopqrstuvwxyz123456789(){},+-*/%;=
.
Ihr Code muss die Anzahl der Punkte ausgeben, die die Aufgabe des Schülers gemäß der folgenden Rubrik erhalten soll:
- Die Eingabe ist
translation-unit
laut Grammatik nicht gültig : 0 Punkte - Die Eingabe folgt der Grammatik, ist jedoch gemäß den folgenden Regeln nicht "wohlgeformt": 1 Punkt
- Die Eingabe ist eine wohlgeformte Übersetzungseinheit, jedoch nicht vollständig modular: 2 Punkte
- Der Eingang ist eine vollständig modulare, wohlgeformte Übersetzungseinheit: 3 Punkte
Token-Definitionen
identifier
: Beliebige Folge von 1 oder mehr englischen Kleinbuchstaben. Wenn ein Bezeichner ein reserviertes C89-Wort 1 ist , können Sie optional 0 zurückgeben, anstatt das Ergebnis, das reservierte Wörter ignoriert hätte. Sie müssen nicht konsequent sein, um die Verwendung reservierter Wörter als Bezeichner zu erkennen. Sie können sie in einigen Fällen markieren und in anderen passieren lassen.integer-literal
: Eine Folge von 1 oder mehr der Ziffern 1-9 (denken Sie daran, dass das Zeichen0
garantiert nicht in der Eingabe erscheint)- Andere gültige Token werden in der Grammatik wörtlich definiert.
- Ein Zeichen muss genau dann zu einem Token gehören, wenn es kein Leerzeichen ist.
- Zwei aufeinanderfolgende alphanumerische Zeichen müssen Teil desselben Tokens sein.
EBNF-Grammatik
var-expr = identifier
literal-expr = integer-literal
binary-op = "+" | "-" | "*" | "/" | "%"
binary-expr = expr binary-op expr
paren-expr = "(" expr ")"
call-expr = identifier "(" [ expr ( "," expr )* ] ")"
expr = var-expr | literal-expr | binary-expr | paren-expr | call-expr
assign-stmt = var-expr "=" expr ";"
if-stmt = "if" "(" expr ")" assign-stmt
return-stmt = "return" expr ";"
function-body = ( assign-stmt | if-stmt )* return-stmt
argument-list = [ identifier ( "," identifier )* ]
function-definition = identifier "(" argument-list ")" "{" function-body "}"
translation-unit = function-definition*
Gut geformte Programmanforderungen
- Keine zwei Funktionsdefinitionen dürfen denselben Funktionsnamen haben.
- Keine zwei Bezeichner in einem
argument-list
dürfen identisch sein. - Kein Bezeichner in a
argument-list
darf mit einem Funktionsnamen identisch sein (ob von afunction-definition
oder acall-expr
). - Die Kennung in a
var-expr
muss in den umschließenden Funktionen enthalten seinargument-list
. - Für eine gegebene Funktion müssen alle
call-expr
s undfunction-definition
(falls vorhanden) in der Anzahl der Argumente übereinstimmen.
Voll modular
- Nicht mehr als 1 Binäroperator pro Funktion
- Nicht mehr als 1 Zuweisungsanweisung pro Funktion
- Nicht mehr als 1 Funktionsaufruf pro Funktion
Beispiele (eines pro Zeile)
Punktzahl 0
}}}}}
return 2;
f() { return -1; }
f() {}
f(x,) { return 1; }
f(x) { return 1 }
f(x) { returnx; }
f(x) { return1; }
f() { g(); return 1;}
f() { if(1) return 5; }
f(x) { if(1) if(1) x = 2; return x; }
f(x, y) { x = y = 2; return x; }
Punktzahl 1
f(){ return 1; } f(){ return 1; }
g(x, x) { return 1; }
g(f) { return 1; } f() { return 1; }
f(x) { x = write(); x = write(1); return 1; }
f() { return f(f); }
f() { return 1; } g() { return f(234567); }
f() { return(x); }
f() { j = 7; return 5; }
Punktzahl 2
f(x,y,zzzzz) { return x + y + zzzzz; }
f(x,a,b) { if(a) x = foo(); if(b) x = bar(); return x; }
f(j) { return g(h( i() / j, i() ), 1) ; }
Punktzahl 3
mod(x, y) { return ((x % y)); }
f() { return f(); }
f(c) { if(c) c = g(c) + 2; return c; }
fib(i){return bb(i,0,1);}aa(i,a,b){return bb(i,b,a+b);}bb(i,a,b){if(i)a=aa(i-1,a,b);return a;}
Punktzahl 0 oder 1
h(auto, auto) { return 1; }
Punktzahl 0 oder 3
if() { return 1; }
1 Reservierte Wortliste:auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while
write
es einmal ohne Argument und einmal mit einem Argument aufgerufen wurde?Antworten:
JavaScript (ES6), 599 Byte
Probieren Sie es online aus! (kommt mit Testfällen)
Definiert eine Funktion
f
, die den Code als Argument verwendet.(Einige) Erklärung
Diese Monstrosität ist im Wesentlichen ein riesiges rekursives bitweises UND, das irgendwie als Parser für diese C-Teilmenge fungiert. Scores werden jeweils als
0137
für gespeichert0123
und am Ende als konvertiertlog2(score+1)
; Wenn eine Phase ein Problem im Code feststellt, gibt sie eine Punktzahl unter 7 zurück, wodurch wiederum Bits von der endgültigen Ausgabe entfernt werden und eine niedrigere Punktzahl erzielt wird. Alle Funktionen außerT
undB
geben eine Punktzahl zurück.Verwendete Bezeichner werden nachverfolgt
L
und Funktionsargumente zählen nachU
. Die Anzahl der Argumente der aktuellen Funktion istN
und die Namen sind inA
. Zuordnungen, binäre Operatoren und Anrufe Verfolgt werden inx
,y
undz
jeweils.Wenn der Code keine Eingabe mehr hat, wird er einfach weiterhin glücklich
undefined
von der Token-Deque entfernt. Dies ist in Ordnung, da die einzige Funktion, die übereinstimmt,undefined
istJ
und alles irgendwann rekursiv beendet wird und 0 zurückgibt , da ein Abschluss nicht übereinstimmt}
. (Mit Ausnahme vonS
undQ
mit expliziten Überprüfungen für das Ende der Eingabe.) Selbst dasundefined
Zurückschieben der Deque ist harmlos, da das Poppenundefined
dasselbe ist wie das Poppen eines leeren Arrays.quelle