Skip to content

Instantly share code, notes, and snippets.

@chriskiefer
Last active March 29, 2022 16:34
Show Gist options
  • Save chriskiefer/c845290eb2d8495a185fe32e342a9809 to your computer and use it in GitHub Desktop.
Save chriskiefer/c845290eb2d8495a185fe32e342a9809 to your computer and use it in GitHub Desktop.
removing sources of ambiguity
# GRAMMAR FOR GODTI LANGUAGE
# (Godti? it's from Transmetropolitan)
# Lexer [or tokenizer] definition with language lexemes [or tokens]
# number: /([0-9]+\.?[0-9]*)|(\.[0-9]+)/, (//doen't work)
@{%
/*
examples:
.sy1 {=p|sawb =p}
~.sy1 100
*/
const lexer = moo.compile({
commaseparator: /,/,
paramEnd: /\)/,
paramBegin: /\(/,
listEnd: /\]/,
listBegin: /\[/,
mappingEnd: />/,
mappingBeginFn: /<[mlenp]/,
mappingBegin: /</,
semicolonSeparator: /;/,
seqBegin: /\|\|/,
stepBegin: /\|:/,
selxBegin: /\|\\x/,
selBegin: /\|\\/,
barToken: /\|/,
lambdaEnd: /}/,
lambdaBegin: /{/,
dacoutCh: /\~[0-9]+/,
dacout: /\~/,
sample: { match: /\*[a-zA-Z0-9]+/, lineBreaks: true, value: x => x.slice(1, x.length)},
lambdaName: {match: /\.[a-zA-Z0-9]+/, value: x => x.slice(1,x.length)},
beatBarIdent: {match:/b[0-9]+b[0-9]+/, value: x => x.slice(1,x.length)},
variable: {match: /=[a-zA-Z0-9]+/, value: x => x.slice(1,x.length)},
fraction: /[0-9]+\/[1-9][0-9]*/,
number: /-?(?:[0-9]|[1-9][0-9]+)(?:\.[0-9]+)?\b/,
semicolon: /;/,
funcName: /[a-zA-Z][a-zA-Z0-9]*/,
string: { match: /'[a-zA-Z0-9]+'/, value: x => x.slice(1,x.length-1)},
newline: { match: /\n+/, lineBreaks: true},
comment: /\/\/[^\n]*/,
ws: { match: /\s+/, lineBreaks: true},
});
function mapping(d, signalIn) {
let val = signalIn;
switch(d['fn']) {
case 'm':
val = sema.synth('mul', [d['p0'], val]);
if (d['p1']) {
val = sema.synth('add', [d['p1'], val]);
};
break;
case 'l':
val = sema.synth('blin', [ val, d['p0'], d['p1'] ]);
break;
case 'e':
val = sema.synth('bexp', [ val, d['p0'], d['p1'] ]);
break;
case 'n':
val = sema.synth('ulin', [ val, d['p0'], d['p1'] ]);
break;
case 'p':
val = sema.synth('uexp', [ val, d['p0'], d['p1'] ]);
break;
}
return val;
};
function beatBarNum(d) {
let vals = d.split('b');
let res = sema.synth( 'bb2ms', [{ '@float': vals[0] } ,{ '@float': vals[1] } ] );
return res;
}
function sequence(seq,phase) {
//console.log(seq);
// console.log(phase);
//is phase a number?
let phasor = phase;
if (phase['@float']) {
// console.log("not a number");
phasor = sema.synth('clp', [phase]);
}
let synth = sema.synth('rsq', [phasor, {'@list':seq}]);
return synth;
}
function stepper(trig,seq,step) {
// console.log(seq);
// console.log(step);
// console.log(trig);
let synth = sema.synth('step', [trig, {'@list':seq}, step]);
return synth;
}
function select(idx,seq) {
//console.log(seq);
//console.log(idx);
let synth = sema.synth('sel', [idx, {'@list':seq}]);
return synth;
}
function selectx(idx,seq) {
console.log(seq);
console.log(idx);
let synth = sema.synth('selx', [idx, {'@list':seq}]);
return synth;
}
%}
# Pass your lexer object using the @lexer option
@lexer lexer
# Grammar definition in the Extended Backus Naur Form (EBNF)
main -> Statement
{% d => ( { '@lang' : d[0] } ) %}
#statement is one or more expressions
Statement ->
_ Expression _
{% d => [ { '@spawn': d[1] } ] %}
|
_ Expression _ %newline
{% d => [ { '@spawn': d[1] } ] %}
|
_ Expression _ %newline _ Statement
{% d => [ { '@spawn': d[1] } ].concat(d[5]) %}
|
%comment %newline:* Statement
{% d => d[2] %}
Lambda ->
%lambdaBegin _ LambdaVarBlock _ Expression _ %lambdaEnd
{% d=> ({
'@lambda':
{'vars':d[2],
'tree':d[4]}
}) %}
LambdaVarBlock -> LambdaVarList _ %barToken
{% d => (d[0] ) %}
LambdaVarList ->
_
{% d=> [] %}
|
%variable
{% d => ( [ d[0] ] ) %}
|
%variable _ %commaseparator _ LambdaVarList
{% d => [ d[0] ].concat(d[4]) %}
Expression ->
%funcName __ ParamElement
{% d => sema.synth( d[0].value, [d[2]]) %}
|
Mapping _ %funcName __ ParamElement
{%
d => mapping(d[0], sema.synth( d[2].value, [d[4]]) )
%}
|
%funcName _ ParameterList _ ParamElement
{% d => sema.synth( d[0].value, [d[4]].concat(d[2]['@params']) ) %}
|
Mapping _ %funcName _ ParameterList _ ParamElement
{% d => mapping(d[0], sema.synth( d[2].value, [d[6]].concat(d[4]['@params']) )) %}
|
%lambdaName _ Lambda
{% d => sema.setvar( d[0].value, d[2] ) %}
|
%lambdaName _ ParamElement
{% d => ( { '@lambdacall': {'params':[d[2]], 'lambda':d[0] }} ) %}
|
%lambdaName _ ParameterList _ ParamElement
{% d => ( { '@lambdacall': {'params':[d[4]].concat(d[2]['@params']), 'lambda':d[0] }} ) %}
|
%variable _ Expression
{% d => sema.setvar( d[0].value, d[2] ) %}
|
%sample _ ParamElement
{% d => sema.synth( 'sampler', [d[2], sema.str(d[0].value)] ) %}
|
%sample _ ParameterList _ ParamElement
{% d => sema.synth( 'sampler', [d[4]].concat(d[2]['@params']).concat([sema.str(d[0].value)]) ) %}
|
Mapping _ %sample _ ParamElement
{% d => mapping(d[0], sema.synth( 'sampler', [d[4], sema.str(d[2].value)] )) %}
|
Mapping _ %sample _ ParameterList _ ParamElement
{% d => mapping(d[0], sema.synth( 'sampler', [d[6]].concat(d[4]['@params']).concat([sema.str(d[2].value)]) ) ) %}
|
%dacout _ Expression
{% d => sema.synth( 'dac', [d[2]] ) %}
|
%dacoutCh __ Expression
{% d => sema.synth( 'dac', [d[2], sema.num(d[0].value.substr(1))] ) %}
# |
# %seqBegin _ SeqParams _ %semicolonSeparator _ %number _ %seqEnd
# {% d=> sequence(d[2],{ '@float': d[6].value }) %}
|
%seqBegin _ SeqParams _ %semicolonSeparator _ ParamElement _ %barToken
{% d=> sequence(d[2],d[6]) %}
|
%stepBegin _ SeqParams _ %semicolonSeparator _ ParamElement _ %semicolonSeparator _ ParamElement _ %barToken
{% d=> stepper(d[10], d[2], d[6]) %}
|
%selBegin _ SeqParams _ %semicolonSeparator _ ParamElement _ %barToken
{% d=> select(d[6],d[2]) %}
|
%selxBegin _ SeqParams _ %semicolonSeparator _ ParamElement _ %barToken
{% d=> selectx(d[6],d[2]) %}
ParameterList ->
%paramBegin Params %paramEnd
{% d => ( {'@params': d[1]} ) %}
|
%paramBegin _ %paramEnd
{% d => ( { '@params': []} ) %}
Params ->
ParamElement
{% d => ( [ d[0] ] ) %}
|
ParamElement _ %commaseparator _ Params
{% d => [ d[0] ].concat(d[4]) %}
SeqParams ->
ParamElement
{% d => ( [ d[0] ] ) %}
|
ParamElement __ SeqParams
{% d => [ d[0] ].concat(d[2]) %}
ParamElement ->
BeatBarNum
{% id %}
|
%number
{% d => ( { '@float': d[0].value } ) %}
|
%fraction
{% d => ( { '@float': d[0].value } ) %}
|
%string
{% d => ( { '@string': d[0].value } ) %}
|
%variable
{% d => sema.getvar( d[0].value ) %}
|
Mapping _ %variable
{% d => mapping(d[0], sema.getvar( d[2].value )) %}
|
%listBegin Params %listEnd
{% d => ( { '@list': d[1] } )%}
|
Expression
{% id %}
Mapping ->
%mappingBegin _ %mappingEnd
{% d => ({'fn': 'none'}) %}
|
%mappingBegin _ %number _ %mappingEnd
{% d => ({'fn': 'm', 'p0': { '@float': d[2].value }}) %}
|
%mappingBegin _ %number _ %semicolonSeparator _ %number _ %mappingEnd
{% d => ({'fn': 'l', 'p0': { '@float': d[2].value }, 'p1': { '@float': d[6].value }}) %}
|
%mappingBeginFn _ %number _ %semicolonSeparator _ %number _ %mappingEnd
{% d => ({'fn': d[0].value[1], 'p0': { '@float': d[2].value }, 'p1': { '@float': d[6].value }}) %}
BeatBarNum -> _ %beatBarIdent _
{% d=> (beatBarNum(d[1].value)) %}
# Whitespace
_ -> wschar:*
{% function(d) {return null;} %}
__ -> wschar:+
{% function(d) {return null;} %}
wschar -> %ws
{% id %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment