GitHub'da da mevcuttur .
Dart 1.12 ve Pub'a ihtiyacınız var. pub get
Ayrıştırma kütüphanesini yalnızca bağımlılığı indirmek için çalıştırın .
İşte bunun umuduyla 30 dakikadan uzun sürüyor! :Ö
Dil
Çinko, operatörlerin yeniden tanımlanması etrafında yönlendirilir. Dilin içindeki tüm operatörleri kolayca yeniden tanımlayabilirsiniz!
Tipik bir Çinko programının yapısı şöyle görünür:
let
<operator overrides>
in <expression>
Yalnızca iki veri türü vardır: tamsayılar ve kümeler. Küme değişmez diye bir şey yoktur ve boş kümelere izin verilmez.
İfade
Aşağıdakiler Çinko'da geçerli ifadelerdir:
Değişmez
Çinko, 1
ve benzeri tüm normal tamsayı değişmezlerini destekler -2
.
Değişkenler
Çinko değişkenlere sahiptir (çoğu dil gibi). Onlara referans vermek için sadece adı kullanın. Yine çoğu dil gibi!
Ancak, S
Pyth'lere benzeyen özel bir değişken var
Q
. İlk kullandığınızda, standart girişten bir satırda okunur ve bir sayı kümesi olarak yorumlanır. Örneğin, giriş satırı 1234231
kümeye dönüşür {1, 2, 3, 4, 3, 2, 1}
.
ÖNEMLİ NOT!!! Bazı durumlarda, bir operatör geçersiz kılma sonundaki değişmez yanlış bir şekilde ayrıştırılır, bu nedenle onu parantez içine almanız gerekir.
İkili işlemler
Aşağıdaki ikili işlemler desteklenir:
- Toplama yoluyla
+
: 1+1
.
- Çıkarma yoluyla
-
: 1-1
.
- Aracılığıyla Çarpma
*
: 2*2
.
- Bölüm yoluyla
/
: 4/2
.
- İle Eşitlik
=
: 3=3
.
Ek olarak, aşağıdaki unary işlemi de desteklenir:
Öncelik her zaman doğru bir ilişkidir. Bunu geçersiz kılmak için parantez kullanabilirsiniz.
Kümeler üzerinde sadece eşitlik ve uzunluk çalışmaktadır. Bir tamsayının uzunluğunu almaya çalıştığınızda, dize gösteriminde basamak sayısını alırsınız.
Kavrama ayarlama
Kümeleri değiştirmek için Zinc, küme kavrayışlarına sahiptir. Buna benziyorlar:
{<variable>:<set><clause>}
Bir yan tümce ya da bir yan tümce ya da yan tümcedir.
Bir zaman yan tümcesi benziyor ^<expression>
. Şapkayı takip eden ifade bir tamsayı ile sonuçlanmalıdır. When cümlesi kullanıldığında, yalnızca kümedeki expression
sıfır olmayan öğeleri alır . İfade içinde, değişken _
kümedeki geçerli dizine ayarlanacaktır. Bu Python'a kabaca eşdeğerdir:
[<variable> for _, <variable> in enumerate(<set>) when <expression> != 0]
Görünüşe göre bir sıralama cümlesi , $<expression>
kümeyi değerine göre aşağı doğru sıralar <expression>
. Bu Python'a eşittir:
sorted(<set>, key=lambda <variable>: <expression>)[::-1]
İşte bazı anlama örnekleri:
geçersiz kılar
Operatör geçersiz kılma işlemleri, operatörleri yeniden tanımlamanıza izin verir. Buna benziyorlar:
<operator>=<operator>
veya:
<variable><operator><variable>=<expression>
İlk durumda, başka bir operatöre eşit olacak bir operatör tanımlayabilirsiniz. Örneğin, +
aslında aracılığıyla çıkarmayı tanımlayabilirim :
+=-
Bunu yaptığınızda, bir işleci sihirli bir işleç olarak yeniden tanımlayabilirsiniz . İki sihirli operatör var:
join
bir küme ve bir tam sayı alır ve kümenin içeriğine katılır. Örneğin, birleştirmek tamsayı {1, 2, 3}
ile 4
sonuçlanacaktır 14243
.
cut
ayrıca bir küme ve bir tam sayı alır ve kümeyi tamsayının her oluşumunda bölümlendirir. Kullanılması cut
üzerinde {1, 3, 9, 4, 3, 2}
ve 3
yaratacak {{1}, {9, 4}, {2}}
... ANCAK sonuç aslında olacak, böylece herhangi bir tek öğeli setleri, basık vardır {1, {9, 4}, 2}
.
İşte +
operatörü şu şekilde tanımlayan bir örnek join
:
+=join
İkinci durumda, bir işleci verilen ifadeye göre yeniden tanımlayabilirsiniz. Örnek olarak, bu değerleri eklemek için artı işlemini tanımlar ve sonra 1'i ekler:
x+y=1+:x+:y
Ama ne +:
? :
Dahili sürümü her zaman kullanmak için iki nokta üst üste bir operatöre ekleyebilirsiniz . Bu örnek yerleşiğini kullanır +
aracılığıyla +:
birbirine numaralarını eklemek için, o zaman bir 1 ekler (hatırlamak, her şey sağ çağrışımlı).
Uzunluk operatörü geçersiz kılmak gibi görünüyor:
#x=<expression>
Neredeyse tüm yerleşik işlemlerin (eşitlik hariç) setin uzunluğunu belirlemek için bu uzunluk operatörünü kullanacağını unutmayın. Bunu tanımladıysanız:
#x=1
Setler üzerinde çalışan Çinko'nun her bölümü =
sadece verilen setin ilk elemanı üzerinde çalışır.
Birden fazla geçersiz kılma
Birden çok operatörü virgülle ayırarak geçersiz kılabilirsiniz:
let
+=-,
*=/
in 1+2*3
Baskı
Çinko'da hiçbir şeyi doğrudan yazdıramazsınız. Aşağıdaki ifadenin sonucu in
yazdırılacaktır. Bir kümenin değerleri ile ayırıcı birleştirilir. Örneğin, şunu al:
let
...
in expr
Eğer expr
kümesidir {1, 3, {2, 4}}
, 1324
programın, bittikten sonra ekrana basılacaktır.
Hepsini bir araya koy
İşte eklenmiş görünen 2+2
ancak sonucun 5 olmasına neden olan basit bir Çinko programı :
let
x+y=1+:x+:y
in 1+2
Çevirmen
Bu giriyor bin/zinc.dart
:
import 'package:parsers/parsers.dart';
import 'dart:io';
// An error.
class Error implements Exception {
String cause;
Error(this.cause);
String toString() => 'error in Zinc script: $cause';
}
// AST.
class Node {
Obj interpret(ZincInterpreter interp) => null;
}
// Identifier.
class Id extends Node {
final String id;
Id(this.id);
String toString() => 'Id($id)';
Obj interpret(ZincInterpreter interp) => interp.getv(id);
}
// Integer literal.
class IntLiteral extends Node {
final int value;
IntLiteral(this.value);
String toString() => 'IntLiteral($value)';
Obj interpret(ZincInterpreter interp) => new IntObj(value);
}
// Any kind of operator.
class Anyop extends Node {
void set(ZincInterpreter interp, OpFuncType func) {}
}
// Operator.
class Op extends Anyop {
final String op;
final bool orig;
Op(this.op, [this.orig = false]);
String toString() => 'Op($op, $orig)';
OpFuncType get(ZincInterpreter interp) =>
this.orig ? interp.op0[op] : interp.op1[op];
void set(ZincInterpreter interp, OpFuncType func) { interp.op1[op] = func; }
}
// Unary operator (len).
class Lenop extends Anyop {
final bool orig;
Lenop([this.orig = false]);
String toString() => 'Lenop($orig)';
OpFuncType get(ZincInterpreter interp) =>
this.orig ? interp.op0['#'] : interp.op1['#'];
void set(ZincInterpreter interp, OpFuncType func) { interp.op1['#'] = func; }
}
// Magic operator.
class Magicop extends Anyop {
final String op;
Magicop(this.op);
String toString() => 'Magicop($op)';
Obj interpret_with(ZincInterpreter interp, Obj x, Obj y) {
if (op == 'cut') {
if (y is! IntObj) { throw new Error('cannot cut int with non-int'); }
if (x is IntObj) {
return new SetObj(x.value.toString().split(y.value.toString()).map(
int.parse));
} else {
assert(x is SetObj);
List<List<Obj>> res = [[]];
for (Obj obj in x.vals(interp)) {
if (obj == y) { res.add([]); }
else { res.last.add(obj); }
}
return new SetObj(new List.from(res.map((l) =>
l.length == 1 ? l[0] : new SetObj(l))));
}
} else if (op == 'join') {
if (x is! SetObj) { throw new Error('can only join set'); }
if (y is! IntObj) { throw new Error('can only join set with int'); }
String res = '';
for (Obj obj in x.vals(interp)) {
if (obj is! IntObj) { throw new Error('joining set must contain ints'); }
res += obj.value.toString();
}
return new IntObj(int.parse(res));
}
}
}
// Unary operator (len) expression.
class Len extends Node {
final Lenop op;
final Node value;
Len(this.op, this.value);
String toString() => 'Len($op, $value)';
Obj interpret(ZincInterpreter interp) =>
op.get(interp)(interp, value.interpret(interp), null);
}
// Binary operator expression.
class Binop extends Node {
final Node lhs, rhs;
final Op op;
Binop(this.lhs, this.op, this.rhs);
String toString() => 'Binop($lhs, $op, $rhs)';
Obj interpret(ZincInterpreter interp) =>
op.get(interp)(interp, lhs.interpret(interp), rhs.interpret(interp));
}
// Clause.
enum ClauseKind { Where, Sort }
class Clause extends Node {
final ClauseKind kind;
final Node expr;
Clause(this.kind, this.expr);
String toString() => 'Clause($kind, $expr)';
Obj interpret_with(ZincInterpreter interp, SetObj set, Id id) {
List<Obj> res = [];
List<Obj> values = set.vals(interp);
switch (kind) {
case ClauseKind.Where:
for (int i=0; i<values.length; i++) {
Obj obj = values[i];
interp.push_scope();
interp.setv(id.id, obj);
interp.setv('_', new IntObj(i));
Obj x = expr.interpret(interp);
interp.pop_scope();
if (x is IntObj) {
if (x.value != 0) { res.add(obj); }
} else { throw new Error('where clause condition must be an integer'); }
}
break;
case ClauseKind.Sort:
res = values;
res.sort((x, y) {
interp.push_scope();
interp.setv(id.id, x);
Obj x_by = expr.interpret(interp);
interp.setv(id.id, y);
Obj y_by = expr.interpret(interp);
interp.pop_scope();
if (x_by is IntObj && y_by is IntObj) {
return x_by.value.compareTo(y_by.value);
} else { throw new Error('sort clause result must be an integer'); }
});
break;
}
return new SetObj(new List.from(res.reversed));
}
}
// Set comprehension.
class SetComp extends Node {
final Id id;
final Node set;
final Clause clause;
SetComp(this.id, this.set, this.clause);
String toString() => 'SetComp($id, $set, $clause)';
Obj interpret(ZincInterpreter interp) {
Obj setobj = set.interpret(interp);
if (setobj is SetObj) {
return clause.interpret_with(interp, setobj, id);
} else { throw new Error('set comprehension rhs must be set type'); }
}
}
// Operator rewrite.
class OpRewrite extends Node {
final Anyop op;
final Node value;
final Id lid, rid; // Can be null!
OpRewrite(this.op, this.value, [this.lid, this.rid]);
String toString() => 'OpRewrite($lid, $op, $rid, $value)';
Obj interpret(ZincInterpreter interp) {
if (lid != null) {
// Not bare.
op.set(interp, (interp,x,y) {
interp.push_scope();
interp.setv(lid.id, x);
if (rid == null) { assert(y == null); }
else { interp.setv(rid.id, y); }
Obj res = value.interpret(interp);
interp.pop_scope();
return res;
});
} else {
// Bare.
if (value is Magicop) {
op.set(interp, (interp,x,y) => value.interpret_with(interp, x, y));
} else {
op.set(interp, (interp,x,y) => (value as Anyop).get(interp)(x, y));
}
}
return null;
}
}
class Program extends Node {
final List<OpRewrite> rws;
final Node expr;
Program(this.rws, this.expr);
String toString() => 'Program($rws, $expr)';
Obj interpret(ZincInterpreter interp) {
rws.forEach((n) => n.interpret(interp));
return expr.interpret(interp);
}
}
// Runtime objects.
typedef Obj OpFuncType(ZincInterpreter interp, Obj x, Obj y);
class Obj {}
class IntObj extends Obj {
final int value;
IntObj(this.value);
String toString() => 'IntObj($value)';
bool operator==(Obj rhs) => rhs is IntObj && value == rhs.value;
String dump() => value.toString();
}
class SetObj extends Obj {
final List<Obj> values;
SetObj(this.values) {
if (values.length == 0) { throw new Error('set cannot be empty'); }
}
String toString() => 'SetObj($values)';
bool operator==(Obj rhs) => rhs is SetObj && values == rhs.values;
String dump() => values.map((x) => x.dump()).reduce((x,y) => x+y);
List<Obj> vals(ZincInterpreter interp) {
Obj lenobj = interp.op1['#'](interp, this, null);
int len;
if (lenobj is! IntObj) { throw new Error('# operator must return an int'); }
len = lenobj.value;
if (len < 0) { throw new Error('result of # operator must be positive'); }
return new List<Obj>.from(values.getRange(0, len));
}
}
// Parser.
class ZincParser extends LanguageParsers {
ZincParser(): super(reservedNames: ['let', 'in', 'join', 'cut']);
get start => prog().between(spaces, eof);
get comma => char(',') < spaces;
get lp => symbol('(');
get rp => symbol(')');
get lb => symbol('{');
get rb => symbol('}');
get colon => symbol(':');
get plus => symbol('+');
get minus => symbol('-');
get star => symbol('*');
get slash => symbol('/');
get eq => symbol('=');
get len => symbol('#');
get in_ => char(':');
get where => char('^');
get sort => char('\$');
prog() => reserved['let'] + oprw().sepBy(comma) + reserved['in'] + expr() ^
(_1,o,_2,x) => new Program(o,x);
oprw() => oprw1() | oprw2() | oprw3();
oprw1() => (basicop() | lenop()) + eq + (magicop() | op()) ^
(o,_,r) => new OpRewrite(o,r);
oprw2() => (id() + op() + id()).list + eq + expr() ^
(l,_,x) => new OpRewrite(l[1], x, l[0], l[2]);
oprw3() => lenop() + id() + eq + expr() ^ (o,a,_,x) => new OpRewrite(o, x, a);
magicop() => (reserved['join'] | reserved['cut']) ^ (s) => new Magicop(s);
basicop() => (plus | minus | star | slash | eq) ^ (op) => new Op(op);
op() => (basicop() + colon ^ (op,_) => new Op(op.op, true)) | basicop();
lenop() => (len + colon ^ (_1,_2) => new Lenop(true)) |
len ^ (_) => new Lenop();
expr() => setcomp() | unop() | binop() | prim();
setcomp() => lb + id() + in_ + rec(expr) + clause() + rb ^
(_1,i,_2,x,c,_3) => new SetComp(i,x,c);
clausekind() => (where ^ (_) => ClauseKind.Where) |
(sort ^ (_) => ClauseKind.Sort);
clause() => clausekind() + rec(expr) ^ (k,x) => new Clause(k,x);
unop() => lenop() + rec(expr) ^ (o,x) => new Len(o,x);
binop() => prim() + op() + rec(expr) ^ (l,o,r) => new Binop(l,o,r);
prim() => id() | intlit() | parens(rec(expr));
id() => identifier ^ (i) => new Id(i);
intlit() => intLiteral ^ (i) => new IntLiteral(i);
}
// Interpreter.
class ZincInterpreter {
Map<String, OpFuncType> op0, op1;
List<Map<String, Obj>> scopes;
ZincInterpreter() {
var beInt = (v) {
if (v is IntObj) { return v.value; }
else { throw new Error('argument to binary operator must be integer'); }
};
op0 = {
'+': (_,x,y) => new IntObj(beInt(x)+beInt(y)),
'-': (_,x,y) => new IntObj(beInt(x)-beInt(y)),
'*': (_,x,y) => new IntObj(beInt(x)*beInt(y)),
'/': (_,x,y) => new IntObj(beInt(x)/beInt(y)),
'=': (_,x,y) => new IntObj(x == y ? 1 : 0),
'#': (i,x,_2) =>
new IntObj(x is IntObj ? x.value.toString().length : x.values.length)
};
op1 = new Map<String, OpFuncType>.from(op0);
scopes = [{}];
}
void push_scope() { scopes.add({}); }
void pop_scope() { scopes.removeLast(); }
void setv(String name, Obj value) { scopes[scopes.length-1][name] = value; }
Obj getv(String name) {
for (var scope in scopes.reversed) {
if (scope[name] != null) { return scope[name]; }
}
if (name == 'S') {
var input = stdin.readLineSync() ?? '';
var list = new List.from(input.codeUnits.map((c) =>
new IntObj(int.parse(new String.fromCharCodes([c])))));
setv('S', new SetObj(list));
return getv('S');
} else throw new Error('undefined variable $name');
}
}
void main(List<String> args) {
if (args.length != 1) {
print('usage: ${Platform.script.toFilePath()} <file to run>');
return;
}
var file = new File(args[0]);
if (!file.existsSync()) {
print('cannot open ${args[0]}');
return;
}
Program root = new ZincParser().start.parse(file.readAsStringSync());
ZincInterpreter interp = new ZincInterpreter();
var res = root.interpret(interp);
print(res.dump());
}
Ve bu içeri giriyor pubspec.yaml
:
name: zinc
dependencies:
parsers: any
Amaçlanan çözüm
let
#x=((x=S)*(-2))+#:x,
/=cut
in {y:{x:S/0$#:x}^_=2}