Esame

data una grammatica mostrare che e riconoscibile per mezzo di $LL(1)$

Grammatica

Pumping lemma per dimostrare che non e di tipo 3

si dimostra per mezzo della stringa $d^ncc^n$ in cui non e identificabile il pezzo centrale per effettuare la scomposizione nei tre pezzi $xwy$ in quanto il pezzo centrale ripetuto non e in grado di generare le due parti della stringa

🔷 si vedeva subito anche dal fatto che la prima regola di produzione presenta self embedding e il corrispondente automa a stati finiti avrebbe avuto infiniti stati

Calcolo dei director symbols set

si ha un conflitto nei director symbols set che riguardano il metasimbolo $c$ dato che si ha $dss(c \rightarrow c)$ non disgiunto con $dss(c\rightarrow cd)$ la grammatica non e $ll(1)$

mostrare che la ricorsione sinistra si può rimuovere ma si ottiene una grammatica diversa

Rimozione della ricorsione sinistra

La ricorsione sinistra e rimovibile ma si ottiene una grammatica diversa, non ottimale in caso si voglia applicare una semantica

tentare l’approccio con analisi $LR(0)$ e $SLR$ per verificare se si può mantenere la ricorsione sinistra senza modificare il linguaggio

Calcolo dei contesti sinistri

Calcolo dei contesti lr(0)

La grammatica in questione non risulta essere lr(0) in quanto la regola di produzione $B \rightarrow \epsilon$ genera un conflitto shift/reduce nell’automa

🔷 Note

per essere $LR(0)$ non devono esserci ricorsioni destre del tipo $A\rightarrow aA|a$ ne produzioni dello stesso metasimbolo che iniziano con la stessa forma di frase e si differiscono per un terminale $S\rightarrow B|Ba$, neanche le produzioni della forma $B\rightarrow bB|\epsilon$ sono corrette in quanto generano nel automa conflitti shift/reduce per via dell $\epsilon$-mossa

Calcolo degli insiemi $follow_1$

e i conseguenti contesti $SLR$

La grammatica risulta essere $SLR$

Costrutto lesect

Costrutto per eseguire una data azione su tutti gli elementi di un array uguali a un dato target

lesect(oggetto_da_iterare,target){funzione da svolgere sull'oggetto}

Scala

def lesect[T](a:Iterable[T],t:T)(expr:(T) =>Unit):Unit={
	if (!a.isEmpty){
		if (a.head == t) expr(a.head)
		lesect(a.drop(1),t)(expr)
	}
}
//il chiamante puo sfruttare la block like sintax e il costrutto e completato
val a=Array("a","b","b")
lesect(a,"b"){print}

Javascript

function lesect(iterable,target){
  return function(expr){
    if (iterable.length!==0){
      if (iterable[0] === target){expr(iterable[0])}
      lesect(iterable.slice(1),target)(expr)
    }
  }
}

var a=Array("a","b","b")
lesect(a,"a")(console.log)
lesect(a,"b")(console.log)
lesect(a,"c")(console.log)

Il cacciavite del sistemista (grep dei poveri)

con il potentissimo costrutto lesect e la possibilità offerta da javascript di costruire funzioni dinamicamente si possono ricreare molti tool unix semplicemente modificando un file,

const readline = require('readline');
const lesect = require('./lesect.js')
const fs = require('node:fs');

// check sui parametri
if (process.argv.length<4){console.error("wrong parameters"); process.exit(1)}

try {
  var commandfile=process.argv[2]
  var target=process.argv[3]
  const commandBody = fs.readFileSync(commandfile, 'utf8');
  var commmand= Function("x",file)
  var lines = [];

  var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal:false
  });

  rl.on('line', (line) => {
    lines.push(line);
  });
  // approssimazione pessima, in questo modo non si consuma input prima di averne concluso la lettura, crash assicurato
  rl.on('close', (line) => {
    lesect(lines,target)(command)
  });

} catch (err) {
  process.exit(1)
}

e cosi possibile cambiare la semantica del costrutto lesect a runtime per mezzo di un semplice file javascript

console.log
console.log(x.replace(process.argv[3],process.argv[4]))

esempi di chiamate

echo -e "a\nb\nb" | node mktool.js poorgrep.txt b
echo -e "a\nb\nb" | node mktool.js poorsed.txt a c

Tratti di scala: le reverse pipes

Mostrare come scala risolve il problema dell’ereditarietà multipla per mezzo dei tratti, e le limitazioni dei tratti parametrici

// GIRA SOLO SU SCALA 3, TESTARE QUI https://scastie.scala-lang.org
class Pipe(var input:String){
	def run():Unit={
		print(input)
	}
}
trait grep(regex:String) extends Pipe{
  override def run():Unit={
    input= input.split("\\\\n").filter((x)=>{x.contains(regex)}).toList.mkString("\n");
    super.run();
  }
}
trait sed(regex:String,replace:String) extends Pipe{
  override def run():Unit={
    input= input.split("\\\\n").toList.map(x => x.replaceAll(regex,replace)).mkString("\n");
    super.run();
  }
}
(new Pipe("hello world")  with grep("pippo") with sed("hello","pippo") ).run()

Non e possibile creare reverse pipes con comandi ripetuti perché un tratto parametrico se esteso due volte con parametro non può essere linearizzato

class PipeGrepSed extends Pipe("Hello world") with grep("pippo") with sed("hello","pippo")
class PipeGrepSedGrep extends PipeGrepSed with grep("world")

🔴 questo non compila perché la seconda classe cerca di richiamare il costruttore del tratto grep() che viene già chiamato dalla classe padre