function semFile(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.ruleNames = new NameList();
data.udtNames = new NameList();
data.rules = [];
data.udts = [];
data.rulesLineMap = [];
data.opcodes = [];
data.altStack = [];
data.topStack = null;
data.topRule = null;
} else if (state === id.SEM_POST) {
let nameObj;
data.rules.forEach((rule) => {
rule.isBkr = false;
rule.opcodes.forEach((op) => {
if (op.type === id.RNM) {
nameObj = data.ruleNames.get(op.index.name);
if (nameObj === -1) {
data.errors.push({
line: data.findLine(data.lines, op.index.phraseIndex, data.charsLength),
char: op.index.phraseIndex,
msg: `Rule name '${op.index.name}' used but not defined.`,
});
op.index = -1;
} else {
op.index = nameObj.index;
}
}
});
});
data.udts.forEach((udt) => {
udt.isBkr = false;
});
data.rules.forEach((rule) => {
rule.opcodes.forEach((op) => {
if (op.type === id.BKR) {
rule.hasBkr = true;
nameObj = data.ruleNames.get(op.index.name);
if (nameObj !== -1) {
data.rules[nameObj.index].isBkr = true;
op.index = nameObj.index;
} else {
nameObj = data.udtNames.get(op.index.name);
if (nameObj !== -1) {
data.udts[nameObj.index].isBkr = true;
op.index = data.rules.length + nameObj.index;
} else {
data.errors.push({
line: data.findLine(data.lines, op.index.phraseIndex, data.charsLength),
char: op.index.phraseIndex,
msg: `Back reference name '${op.index.name}' refers to undefined rule or unamed UDT.`,
});
op.index = -1;
}
}
}
});
});
}
return ret;
}
function semRule(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.altStack.length = 0;
data.topStack = null;
data.rulesLineMap.push({
line: data.findLine(data.lines, phraseIndex, data.charsLength),
char: phraseIndex,
});
}
return ret;
}
function semRuleLookup(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.ruleName = '';
data.definedas = '';
} else if (state === id.SEM_POST) {
let ruleName;
if (data.definedas === '=') {
ruleName = data.ruleNames.add(data.ruleName);
if (ruleName === -1) {
data.definedas = null;
data.errors.push({
line: data.findLine(data.lines, phraseIndex, data.charsLength),
char: phraseIndex,
msg: `Rule name '${data.ruleName}' previously defined.`,
});
} else {
data.topRule = {
name: ruleName.name,
lower: ruleName.lower,
opcodes: [],
index: ruleName.index,
};
data.rules.push(data.topRule);
data.opcodes = data.topRule.opcodes;
}
} else {
ruleName = data.ruleNames.get(data.ruleName);
if (ruleName === -1) {
data.definedas = null;
data.errors.push({
line: data.findLine(data.lines, phraseIndex, data.charsLength),
char: phraseIndex,
msg: `Rule name '${data.ruleName}' for incremental alternate not previously defined.`,
});
} else {
data.topRule = data.rules[ruleName.index];
data.opcodes = data.topRule.opcodes;
}
}
}
return ret;
}
function semAlternation(state, chars, phraseIndex, phraseCount, data) {
let ret = id.SEM_OK;
if (state === id.SEM_PRE) {
const TRUE = true;
while (TRUE) {
if (data.definedas === null) {
ret = id.SEM_SKIP;
break;
}
if (data.topStack === null) {
if (data.definedas === '=') {
data.topStack = {
alt: {
type: id.ALT,
children: [],
},
cat: null,
};
data.altStack.push(data.topStack);
data.opcodes.push(data.topStack.alt);
break;
}
data.topStack = {
alt: data.opcodes[0],
cat: null,
};
data.altStack.push(data.topStack);
break;
}
data.topStack = {
alt: {
type: id.ALT,
children: [],
},
cat: null,
};
data.altStack.push(data.topStack);
data.opcodes.push(data.topStack.alt);
break;
}
} else if (state === id.SEM_POST) {
data.altStack.pop();
if (data.altStack.length > 0) {
data.topStack = data.altStack[data.altStack.length - 1];
} else {
data.topStack = null;
}
}
return ret;
}
function semConcatenation(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.topStack.alt.children.push(data.opcodes.length);
data.topStack.cat = {
type: id.CAT,
children: [],
};
data.opcodes.push(data.topStack.cat);
} else if (state === id.SEM_POST) {
data.topStack.cat = null;
}
return ret;
}
function semRepetition(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.topStack.cat.children.push(data.opcodes.length);
}
return ret;
}
function semOptionOpen(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.REP,
min: 0,
max: 1,
char: phraseIndex,
});
}
return ret;
}
function semRuleName(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.ruleName = apglib.utils.charsToString(chars, phraseIndex, phraseCount);
}
return ret;
}
function semDefined(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.definedas = '=';
}
return ret;
}
function semIncAlt(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.definedas = '=/';
}
return ret;
}
function semRepOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.min = 0;
data.max = Infinity;
data.topRep = {
type: id.REP,
min: 0,
max: Infinity,
};
data.opcodes.push(data.topRep);
} else if (state === id.SEM_POST) {
if (data.min > data.max) {
data.errors.push({
line: data.findLine(data.lines, phraseIndex, data.charsLength),
char: phraseIndex,
msg: `repetition min cannot be greater than max: min: ${data.min}: max: ${data.max}`,
});
}
data.topRep.min = data.min;
data.topRep.max = data.max;
}
return ret;
}
function semRepMin(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.min = decnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semRepMax(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.max = decnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semRepMinMax(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.max = decnum(chars, phraseIndex, phraseCount);
data.min = data.max;
}
return ret;
}
function semAndOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.AND,
});
}
return ret;
}
function semNotOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.NOT,
});
}
return ret;
}
function semRnmOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.RNM,
index: {
phraseIndex,
name: apglib.utils.charsToString(chars, phraseIndex, phraseCount),
},
});
}
return ret;
}
function semAbgOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.ABG,
});
}
return ret;
}
function semAenOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.AEN,
});
}
return ret;
}
function semBkaOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.BKA,
});
}
return ret;
}
function semBknOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.opcodes.push({
type: id.BKN,
});
}
return ret;
}
function semBkrOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.ci = true;
data.cs = false;
data.um = true;
data.pm = false;
} else if (state === id.SEM_POST) {
data.opcodes.push({
type: id.BKR,
bkrCase: data.cs === true ? id.BKR_MODE_CS : id.BKR_MODE_CI,
bkrMode: data.pm === true ? id.BKR_MODE_PM : id.BKR_MODE_UM,
index: {
phraseIndex: data.bkrname.phraseIndex,
name: apglib.utils.charsToString(chars, data.bkrname.phraseIndex, data.bkrname.phraseLength),
},
});
}
return ret;
}
function semBkrCi(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.ci = true;
}
return ret;
}
function semBkrCs(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.cs = true;
}
return ret;
}
function semBkrUm(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.um = true;
}
return ret;
}
function semBkrPm(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.pm = true;
}
return ret;
}
function semBkrName(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.bkrname = {
phraseIndex,
phraseLength: phraseCount,
};
}
return ret;
}
function semUdtEmpty(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
const name = apglib.utils.charsToString(chars, phraseIndex, phraseCount);
let udtName = data.udtNames.add(name);
if (udtName === -1) {
udtName = data.udtNames.get(name);
if (udtName === -1) {
throw new Error('semUdtEmpty: name look up error');
}
} else {
data.udts.push({
name: udtName.name,
lower: udtName.lower,
index: udtName.index,
empty: true,
});
}
data.opcodes.push({
type: id.UDT,
empty: true,
index: udtName.index,
});
}
return ret;
}
function semUdtNonEmpty(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
const name = apglib.utils.charsToString(chars, phraseIndex, phraseCount);
let udtName = data.udtNames.add(name);
if (udtName === -1) {
udtName = data.udtNames.get(name);
if (udtName === -1) {
throw new Error('semUdtNonEmpty: name look up error');
}
} else {
data.udts.push({
name: udtName.name,
lower: udtName.lower,
index: udtName.index,
empty: false,
});
}
data.opcodes.push({
type: id.UDT,
empty: false,
index: udtName.index,
syntax: null,
semantic: null,
});
}
return ret;
}
function semTlsOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.tlscase = true;
}
return ret;
}
function semTlsCase(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
if (phraseCount > 0 && (chars[phraseIndex + 1] === 83 || chars[phraseIndex + 1] === 115)) {
data.tlscase = false;
}
}
return ret;
}
function semTlsString(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
if (data.tlscase) {
const str = chars.slice(phraseIndex, phraseIndex + phraseCount);
for (let i = 0; i < str.length; i += 1) {
if (str[i] >= 65 && str[i] <= 90) {
str[i] += 32;
}
}
data.opcodes.push({
type: id.TLS,
string: str,
});
} else {
data.opcodes.push({
type: id.TBS,
string: chars.slice(phraseIndex, phraseIndex + phraseCount),
});
}
}
return ret;
}
function semClsOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
if (phraseCount <= 2) {
data.opcodes.push({
type: id.TLS,
string: [],
});
} else {
data.opcodes.push({
type: id.TBS,
string: chars.slice(phraseIndex + 1, phraseIndex + phraseCount - 1),
});
}
}
return ret;
}
function semTbsOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.tbsstr = [];
} else if (state === id.SEM_POST) {
data.opcodes.push({
type: id.TBS,
string: data.tbsstr,
});
}
return ret;
}
function semTrgOp(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.min = 0;
data.max = 0;
} else if (state === id.SEM_POST) {
if (data.min > data.max) {
data.errors.push({
line: data.findLine(data.lines, phraseIndex, data.charsLength),
char: phraseIndex,
msg: `TRG, (%dmin-max), min cannot be greater than max: min: ${data.min}: max: ${data.max}`,
});
}
data.opcodes.push({
type: id.TRG,
min: data.min,
max: data.max,
});
}
return ret;
}
function semDmin(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.min = decnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semDmax(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.max = decnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semBmin(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.min = binnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semBmax(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.max = binnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semXmin(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.min = hexnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semXmax(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.max = hexnum(chars, phraseIndex, phraseCount);
}
return ret;
}
function semDstring(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.tbsstr.push(decnum(chars, phraseIndex, phraseCount));
}
return ret;
}
function semBstring(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.tbsstr.push(binnum(chars, phraseIndex, phraseCount));
}
return ret;
}
function semXstring(state, chars, phraseIndex, phraseCount, data) {
const ret = id.SEM_OK;
if (state === id.SEM_POST) {
data.tbsstr.push(hexnum(chars, phraseIndex, phraseCount));
}
return ret;
}