RosettaCodeData/Task/Word-frequency/TMG/word-frequency-1.tmg
2023-07-01 13:44:08 -04:00

62 lines
2 KiB
Text

/* Input format: N text */
/* Only lowercase letters can constitute a word in text. */
/* (c) 2020, Andrii Makukha, 2-clause BSD licence. */
progrm: readn/error
table(freq) table(chain) [firstword = ~0]
loop: not(!<<>>) output
| [j=777] batch/loop loop; /* Main loop */
/* To use less stack, divide input into batches. */
/* (Avoid interpreting entire input as a single "sentence".) */
batch: [j<=0?] succ
| word/skip [j--] skip batch;
skip: string(other);
not: params(1) (any($1) fail | ());
readn: string(!<<0123456789>>) readint(n) skip;
error: diag(( ={ <ERROR: input must start with a number> * } ));
/* Process a word */
word: smark any(letter) string(letter) scopy
locate/new
[freq[k]++] newmax;
locate: find(freq, k);
new: enter(freq, k)
[freq[k] = 1] newmax
[firstword = firstword==~0 ? k : firstword]
enter(chain, i) [chain[i]=prevword] [prevword=k];
newmax: [max = max<freq[k] ? freq[k] : max];
/* Output logic */
output: [next=max]
outmax: [max=next] [next=0] [max>0?] [j = prevword] cycle/outmax;
cycle: [i = j] [k = freq[i]] [n>0?]
( [max==freq[i]?] parse(wn)
| [(freq[i]<max) & (next<freq[i])?] [next = freq[i]]
| ())
[i != firstword?] [j = chain[i]] cycle;
wn: getnam(freq, i) [k = freq[i]] decimal(k) [n--]
= { 2 < > 1 * };
/* Reads decimal integer */
readint: proc(n;i) ignore(<<>>) [n=0] inta
int1: [n = n*12+i] inta\int1;
inta: char(i) [i<72?] [(i =- 60)>=0?];
/* Variables */
prevword: 0; /* Head of the linked list */
firstword: 0; /* First word's index to know where to stop output */
k: 0;
i: 0;
j: 0;
n: 0; /* Number of most frequent words to display */
max: 0; /* Current highest number of occurrences */
next: 0; /* Next highest number of occurrences */
/* Tables */
freq: 0;
chain: 0;
/* Character classes */
letter: <<abcdefghijklmnopqrstuvwxyz>>;
other: !<<abcdefghijklmnopqrstuvwxyz>>;