Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add %define api.value.type feature, fixes #6 #8

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@
"tslint": "^5.19.0",
"typescript": "^3.8.3"
}
}
}
65 changes: 62 additions & 3 deletions src/languages/parser/yaccParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ enum ParserState {
WaitingPrecedence,
WaitingRule,
WaitingUnion,
WaitingDefine,
WaitingDefineType,
Normal
};

Expand Down Expand Up @@ -53,6 +55,7 @@ export enum NodeType {
Type,
Precedence,
Rule,
Define,
Embedded
};

Expand Down Expand Up @@ -163,6 +166,9 @@ export function parse(text: string): YACCDocument {
let lastNode: Node | undefined;
let lastToken = token;
let lastTokenSymbol = undefined;
let defineType = false;
let unionType = false;
let defineDefaultType = '';
while (end < 0 && token !== TokenType.EOS) {
offset = scanner.getTokenOffset();
switch (token) {
Expand Down Expand Up @@ -190,6 +196,11 @@ export function parse(text: string): YACCDocument {
lastNode.actions.push(scanner.getTokenText());
}
break;
case ParserState.WaitingDefineType: //%define api.value.type {data type}
tokenText = scanner.getTokenText();
defineDefaultType = tokenText;
state = ParserState.Normal;
break;
}
break;
case TokenType.Option:
Expand All @@ -205,6 +216,11 @@ export function parse(text: string): YACCDocument {
tokenText = scanner.getTokenText();
switch (tokenText) {
case '%union':
if(defineType) { //%define api.valu.type was declared
addProblem(`%union and %define api.value.type cannot be used together`, scanner.getTokenOffset(),
scanner.getTokenEnd(), ProblemType.Warning);
}
unionType = true;
state = ParserState.WaitingUnion;
break;
case '%token':
Expand All @@ -222,6 +238,13 @@ export function parse(text: string): YACCDocument {
lastNode = { nodeType: NodeType.Precedence, offset: offset, length: -1, end: -1 }
state = ParserState.WaitingPrecedence;
break;
case '%define':
if(unionType) { //%union was declared
addProblem(`%union and %define api.value.type cannot be used together`, scanner.getTokenOffset(),
scanner.getTokenEnd(), ProblemType.Warning);
}
state = ParserState.WaitingDefine;
break;
default:
break;
}
Expand All @@ -239,10 +262,15 @@ export function parse(text: string): YACCDocument {
// extract the type inside the tag <[type]>
type = scanner.getTokenText();
const t = document.types[type];
if (t) {
if(defineDefaultType !== '' && type !== defineDefaultType) { //type clash
addProblem('Type is not the same as in %define api.value.type', scanner.getTokenOffset(),
scanner.getTokenEnd(), ProblemType.Warning);
} else if(!t && defineType) { //if type is not defined but %define api.value.type is
addSymbolToMap(document.types, true, scanner.getTokenOffset(), scanner.getTokenEnd(), type, type);
} else if (t) {
t.references.push([scanner.getTokenOffset(), scanner.getTokenEnd()]);
} else {
addProblem(`Type was not declared in the %union.`, scanner.getTokenOffset(), scanner.getTokenEnd(), ProblemType.Error);
addProblem(`Type was not declared in the %union or %define.`, scanner.getTokenOffset(), scanner.getTokenEnd(), ProblemType.Error);
}
break;
case TokenType.RulesTag:
Expand Down Expand Up @@ -292,6 +320,35 @@ export function parse(text: string): YACCDocument {
references: [[offset, scanner.getTokenEnd()]]
});
break;
case ParserState.WaitingDefine: //%define met
switch (word) {
case 'api.value.type': //rule for stack data type
if(defineType) {
addProblem(`%define api.value.type was already defined`, scanner.getTokenOffset(),
scanner.getTokenEnd(), ProblemType.Error);
state = ParserState.Normal;
} else {
defineType = true;
state = ParserState.WaitingDefineType;
}
break;
default: //other rules are ignored
state = ParserState.Normal;
break;
}
break;
case ParserState.WaitingDefineType: //%define api.value.type met
switch (word) {
case 'union-directive': //just normal %union
case 'union': //symbols defined with type name, Bison generate a union itself
case 'variant': //same as union but with c++ types ex. std::string
break;
default: //%define api.value.type not matched
addProblem(`Unexpected type ${word}`, offset, scanner.getTokenEnd(), ProblemType.Error);
break;
}
state = ParserState.Normal;
break;
default:
addProblem(`Unexpected symbol ${word}`, offset, scanner.getTokenEnd(), ProblemType.Error);
}
Expand Down Expand Up @@ -330,6 +387,8 @@ export function parse(text: string): YACCDocument {
nonTerminal.references.push(symbol.references[0]); // add %type reference
nonTerminal.type = symbol.type; // assign the type from %type
symbol.references = nonTerminal.references; // update also the old references
} else if(defineDefaultType !== ''){
nonTerminal.type = defineDefaultType;
}
const token = document.tokens[nonTerminal.name];
if (token !== undefined) { // if the symbol was already declared as a token
Expand Down Expand Up @@ -462,7 +521,7 @@ export function parse(text: string): YACCDocument {
const element = node.actions![i];
if (element.indexOf('$$') !== -1) {
const symbol = document.symbols[node.name!];
if (!symbol.type) {
if (!symbol.type && defineDefaultType === '') {
addProblem('Semantic value used inside actions but has not declared the type.',
symbol.offset,
symbol.end,
Expand Down
2 changes: 1 addition & 1 deletion src/languages/parser/yaccScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function createScanner(input: string, initialOffset = 0, initialState: Sc
let tokenError: string | undefined;

function nextWord(): string {
return stream.advanceIfRegExp(/^[a-zA-Z][\w.]*/);
return stream.advanceIfRegExp(/^[a-zA-Z][\w.-]*/);
}

function nextLiteral(): string {
Expand Down